Wireshark & tshark

When the logs disagree with the service, the packets don't lie. Capture, filter, and follow conversations to prove what actually went on the wire.

What it is and when to use it

Wireshark is a protocol analyser: a GUI (wireshark) and a CLI (tshark) that capture packets and dissect them into per-protocol fields (Ethernet, IP, TCP, TLS, HTTP, DNS, SMB, and hundreds more). It reads pcap/pcapng files produced by itself, tcpdump, or any libpcap tool.

When to reach for it vs the alternatives:

ProblemUse
Fast on-box "is there any traffic?" checktcpdump — smaller, always installed
Is a port open?nmap
Which process opened this socket?lsof / ss
What did the TLS handshake actually negotiate?Wireshark (dissects every extension)
Why is HTTP hanging mid-response?Wireshark (tcp.analysis.flags)
SMB client fails, server logs nothing usefulWireshark (full SMB2 dissector)
Workflow: capture with tcpdump on the remote box (no GUI needed), copy the pcap to your laptop, open in Wireshark. This is how almost every real investigation happens.

Capturing traffic

Both wireshark and tshark share the same capture engine (dumpcap). In CI, on servers, or over SSH, use tshark.

# List interfaces
tshark -D

# Capture on eth0 until Ctrl-C, write to file
tshark -i eth0 -w /tmp/cap.pcapng

# Limit what you capture (BPF capture filter)
tshark -i eth0 -f "host 10.0.0.5 and tcp port 443" -w /tmp/tls.pcapng

# Ring buffer: 10 files x 100 MiB each, overwrite oldest
tshark -i eth0 -b filesize:100000 -b files:10 -w /tmp/ring.pcapng

# Stop after N seconds
tshark -i eth0 -a duration:60 -w /tmp/60s.pcapng

# Stop after N packets
tshark -i eth0 -c 2000 -w /tmp/2k.pcapng

Write to a file, read later. Live dissection is slow and consumes memory. Capture narrow and fast with -f, then filter and analyse the pcap offline with display filters.

Reading a pcap

# One-line summary per packet (default)
tshark -r /tmp/cap.pcapng

# Apply a display filter (Wireshark syntax, not BPF)
tshark -r /tmp/cap.pcapng -Y 'tcp.port == 443 and tls.handshake.type == 1'

# Fully expanded dissection of each packet
tshark -r /tmp/cap.pcapng -V

# Hex + ASCII dump of packet payload
tshark -r /tmp/cap.pcapng -x

# Extract specific fields as tab-separated values
tshark -r /tmp/cap.pcapng -Y 'http.request' \
  -T fields -e frame.time -e ip.src -e http.host -e http.request.uri

# Conversation and endpoint summaries
tshark -r /tmp/cap.pcapng -q -z conv,tcp
tshark -r /tmp/cap.pcapng -q -z endpoints,ip
tshark -r /tmp/cap.pcapng -q -z io,stat,1        # packets per second

Capture filters vs display filters

This is the single most common point of confusion. They are two different languages.

Capture filter (-f)Display filter (-Y)
SyntaxBPF (same as tcpdump)Wireshark's own syntax
When it runsAt capture time — packets that don't match are droppedWhen reading the pcap — all packets are in the file
Exampletcp port 443 and host 10.0.0.5tcp.port == 443 && ip.addr == 10.0.0.5
Use it whenCapturing from a busy interface — keep the pcap smallInvestigating a pcap you already have

Rule of thumb: capture narrowly with BPF (-f), then explore widely with display filters (-Y). If you're not sure yet, capture unfiltered for a short time window, then filter offline.

Common display filters

# Addresses and ports
ip.addr == 10.0.0.5
ip.src == 10.0.0.5 and ip.dst == 10.0.0.9
tcp.port == 443
not tcp.port in {22, 53}

# TLS handshake (ClientHello, ServerHello, certificate, alerts)
tls.handshake.type == 1                # ClientHello (check SNI)
tls.handshake.type == 2                # ServerHello
tls.handshake.extensions_server_name   # any with SNI set
tls.alert_message                      # TLS alerts (expired cert, unknown CA…)

# HTTP
http.request                           # every HTTP request
http.request.method == "POST"
http.response.code >= 500
http.host contains "example.com"

# DNS
dns.flags.response == 0                # queries only
dns.qry.name == "example.com"
dns.resp.type == 15                    # MX records

# TCP problems — the diagnostic goldmine
tcp.analysis.retransmission
tcp.analysis.duplicate_ack
tcp.analysis.out_of_order
tcp.analysis.zero_window               # receiver told sender to stop
tcp.flags.reset == 1                   # RST packets

# ICMP (unreachables are often the real answer)
icmp.type == 3                         # destination unreachable
icmp.type == 11                        # TTL exceeded

# SMB / Samba
smb2.cmd == 3                          # Tree Connect
smb2.nt_status != 0x00000000           # any SMB error

Follow streams and conversations

"Follow" reconstructs the application-layer byte stream from scattered TCP segments. Essential for HTTP debugging.

# List conversations so you can pick a stream number
tshark -r cap.pcapng -q -z conv,tcp

# Follow stream 0, ASCII output
tshark -r cap.pcapng -q -z follow,tcp,ascii,0

# Follow a UDP stream
tshark -r cap.pcapng -q -z follow,udp,ascii,2

# In the GUI: right-click a packet → Follow → TCP Stream

Export objects (files) from a pcap

If a protocol carries whole files (HTTP responses, SMB writes, TFTP, IMF email), Wireshark can reassemble and dump them to disk.

mkdir -p /tmp/objs
tshark -r cap.pcapng --export-objects http,/tmp/objs
tshark -r cap.pcapng --export-objects smb,/tmp/objs
tshark -r cap.pcapng --export-objects tftp,/tmp/objs

ls -la /tmp/objs/

Great for recovering what exactly a misbehaving client received — the file on disk is the ground truth the app actually parsed.

Decode-as for non-standard ports

If your service runs on a non-default port (e.g. HTTPS on 8443, or some weird-corporate 9000), Wireshark won't auto-detect the protocol. Tell it explicitly:

# Decode tcp/8443 as TLS
tshark -r cap.pcapng -d tcp.port==8443,tls -Y 'tls.handshake.type == 1'

# Decode tcp/8080 as HTTP
tshark -r cap.pcapng -d tcp.port==8080,http -Y 'http.request'

Permissions: capturing as non-root

Running as root works but isn't ideal. Most distros ship a wireshark group and a setcap-enabled dumpcap.

# RHEL / Rocky / Debian / Ubuntu
sudo usermod -aG wireshark $USER
newgrp wireshark                        # or log out/in

# Verify dumpcap has the capability set (not just setuid)
getcap /usr/bin/dumpcap
# → /usr/bin/dumpcap = cap_net_admin,cap_net_raw+eip

# If it's missing (rare on packaged installs):
sudo setcap 'cap_net_admin,cap_net_raw+eip' /usr/bin/dumpcap

Practical SysAdmin recipes

User says "TLS is broken to api.example.com"

# On the client, capture 30 seconds while they reproduce
tshark -i any -f 'host api.example.com and tcp port 443' \
  -a duration:30 -w /tmp/tls.pcapng

# Did we get a ClientHello, a ServerHello, and a cert?
tshark -r /tmp/tls.pcapng -Y 'tls.handshake.type in {1,2,11}' \
  -T fields -e frame.time -e ip.src -e ip.dst -e tls.handshake.type \
  -e tls.handshake.extensions_server_name

# Any TLS alerts? (expired cert, bad CA, handshake failure…)
tshark -r /tmp/tls.pcapng -Y 'tls.alert_message' -V

An alert with Level: Fatal (2) and Description: bad_certificate (42) points straight at the cert. See Certificates.

"SYN but no SYN-ACK" checklist

# Capture on the client
tshark -i any -f 'host 10.0.0.5 and tcp port 443' -a duration:20 -w /tmp/syn.pcapng

# Count SYN vs SYN-ACK
tshark -r /tmp/syn.pcapng -Y 'tcp.flags.syn == 1 and tcp.flags.ack == 0' | wc -l
tshark -r /tmp/syn.pcapng -Y 'tcp.flags.syn == 1 and tcp.flags.ack == 1' | wc -l

# If SYNs are going out but nothing comes back:
#  1. firewalld / iptables on the destination dropping SYN
#  2. server not listening (confirm with ss -tlnp on the server)
#  3. route/gateway problem (see ICMP unreachables in the pcap)
tshark -r /tmp/syn.pcapng -Y 'icmp'

"Why is this HTTP request hanging?"

# Look for TCP pathology signatures
tshark -r cap.pcapng -Y 'tcp.analysis.flags' -T fields \
  -e frame.time -e ip.src -e ip.dst -e tcp.analysis.flags

# Zero window = the receiving side ran out of buffer space
# Retransmissions = loss on the path OR the server is too slow to ACK
# Dup ACKs = the sender missed a segment, receiver is poking for it

Quick sanity check: what's my host even talking to?

# Top 20 IP conversations on eth0 for 10 seconds
tshark -i eth0 -a duration:10 -q -z conv,ip | head -30

Capture on a remote host, view locally

You don't need Wireshark installed on production. Pipe tcpdump over SSH to a local Wireshark GUI:

# Live pipe: see packets flow into your local Wireshark in real time
ssh prod01 "sudo tcpdump -U -s0 -w - 'not port 22'" | wireshark -k -i -

# Or the two-step version (safer — no live capture pressure on prod)
ssh prod01 "sudo tcpdump -s0 -c 5000 -w - 'host api.example.com'" > /tmp/cap.pcapng
wireshark /tmp/cap.pcapng &

The SSH filter ('not port 22') is important — otherwise you capture your own SSH session too, which is noisy and encrypted.

Related: Linux Networking for tcpdump basics and the general network troubleshoot checklist, NMAP for port and service probing, lsof & strace for which process owns a socket.