tcpdump and Wireshark

On this page

Packet captures save packets collected at a specific observation point over a period of time. tcpdump is suitable for conditional collection and offline inspection, while Wireshark/TShark is suitable for protocol field, reassembly, and timing analysis. Reliable conclusions come from the consistency of "collection scope, protocol facts, and inference boundaries," rather than a single line being highlighted in red.

Question to answer firstImpact on collection
Which part of the connection failedClient, proxy ingress, and proxy egress may require different collection points
TCP or UDP?Capturing only TCP 443 will miss QUIC
Is DNS involved?Capturing only by destination IP may miss preceding resolution failures
Do you want to check handshakes or content?Determines whether to start early, and whether full snaplen and decryption materials are needed
Can it be saved completely?Determines filtering scope, buffering, file rotation, and stop conditions

Observation position determines what you can prove

For the same access, different observation points see different connections and packet shapes Client Application / socket Proxy or NAT Terminates connection or rewrites address Backend service Another connection segment Host packet capture may be before offloading Five-tuple may change after proxy First record interface, namespace, direction, and time base Not seeing a packet only means it wasn't captured here; need to rule out different paths, filtering, truncation, and capture drops.

Linux host, container network namespace, veth, bridge, physical NIC, and loopback are not the same perspective. -i any covers interfaces available for capture in the current namespace and does not automatically enter all containers. Linux's any typically uses a cooked capture link type; do not assume each packet starts with a standard Ethernet header.

After NAT, addresses and ports may change; after a reverse proxy, it is usually another TCP connection, so you cannot use the same tcp.stream or five-tuple to find the backend. Cross-file association requires combining time, request ID, payload characteristics, and proxy logs; stream numbers in each file are just indices in this analysis result.

Capturing at both ends simultaneously can narrow down where the loss occurred, but if clocks are not synchronized, directly subtracting timestamps will produce incorrect one-way latency. Microsecond or nanosecond precision timestamps do not guarantee measurement accuracy at the same level.

Where do capture filters and display filters take effect?

AttributeCapture filterDisplay filter
Common usagetcpdump expressions, TShark -fWireshark filter bar, TShark -Y
TargetPre-collection filtering or offline read filteringFields after existing packets have been parsed
Exampletcp port 443tcp.port == 443
Unmatched dataUsually not written to the capture file during real-time collectionOriginal file is still retained, allowing re-analysis with different conditions
Capability boundariesDepends on link type, offsets, and compiler supportDepends on dissector, reassembly, and visible plaintext

In real-time collection, libpcap can hand the filtering program to the kernel on supported platforms, reducing packets sent to user space; when reading offline files, the same expressions can be used, but it is not true that "all BPF filtering always happens in the kernel." Without given traffic, match ratios, and decoding overhead, one cannot claim it is fixed by several orders of magnitude. tcpdump manual source

Common capture conditions

# The following are filter expressions, passed to tcpdump as a single quoted argument.
# Bidirectional involving destination, covering TCP and UDP 443:
tcpdump -nn -r capture.pcap 'host 192.0.2.10 and port 443'

# Only IPv4 with SYN set and ACK not set; allows other coexistence flags to exist simultaneously:
tcpdump -nn -r capture.pcap 'ip and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn'

# One of two destinations, and TCP 443:
tcpdump -nn -r capture.pcap '(host 192.0.2.10 or host 192.0.2.20) and tcp port 443'

tcp[tcpflags] == tcp-syn is strict equality of the flag byte, which may exclude SYN packets that also have other coexistence flags; bitwise masking accurately expresses "has SYN, no ACK." Raw transport header offset expressions have additional limitations in scenarios like IPv6 extension headers, so IPv4 is explicitly limited here and cannot be treated as a universal connection establishment statistic for all protocols.

Port conditions do not equal application identification: 443 can carry different protocols, and encrypted DNS traffic is not always on port 53. Non-first IP fragments do not have original transport layer ports; overly narrow port filtering may cause missing fragments during reassembly. VLAN and tunnel encapsulation also affect offsets and match ranges. pcap-filter syntax source

Can changing the display filter recover packets that weren't captured?

Using strict equality for collection first, then displaying all, will only show one packet. You must re-collect using masking to save both SYN types. Changing the collection dropdown itself does not rewrite the already saved file; you must explicitly execute a new collection.

Preparing the visual
Can changing the display filter recover packets that weren't captured?

Display filtering can only filter within the saved set. Strict SYN equality will miss SYN packets with ECE/CWR set simultaneously; displaying all afterwards cannot recover them.

Collect controllably, then analyze offline

The following are commands adjusted for the environment during actual troubleshooting. NIC names and target addresses need to be replaced; file locations must be writable; capturing interfaces usually require corresponding permissions, while reading saved files generally does not.

# Process at most 5000 matching packets; -c limits packet count, not wait time.
tcpdump -i eth0 -nn -s 0 -B 4096 -c 5000 \
  -w capture.pcap 'host 192.0.2.10 and port 443'

# Rotate saving 5 files by size, -C 100 base unit is decimal megabytes.
tcpdump -i eth0 -nn -s 0 -C 100 -W 5 \
  -w trace.pcap 'host 192.0.2.10'

# Read-only, do not start capturing.
tcpdump -nn -tttt -r capture.pcap

-s 0 uses the tool-defined maximum/default snaplen, not mathematically infinite length; check the captured length and original length inside the file to know if a packet was truncated. -B unit is KiB. -C rotation may slightly exceed the threshold and cannot be treated as an exact disk limit; combined with -W, it will loop and overwrite old files. Time-based -G and counting options have different interactions; do not directly copy size rotation logic.

At the end, record captured, received by filter, and dropped by kernel. The latter two depend on the operating system; dropped by kernel indicates buffer drops by the capture mechanism, not equal to the actual business network packet loss count. Even if it shows 0, it does not guarantee that the mirror port, driver, or other locations did not miss captures.

A rough storage budget: average 20,000 packets per second, average retained 800 B, classic pcap has an additional 16 B header per record, 60 seconds is approximately 20,000 × 816 × 60 = 979,200,000 B, which is 979.2 MB. This estimate does not account for filesystem overhead and is not applicable for directly calculating all block structures in pcapng.

Locate the stream first, then look at reassembly and direction

# TCP conversation summary; -q reduces per-packet output.
tshark -r capture.pcap -q -z conv,tcp

# Select stream 3 from the same capture file and export key fields.
tshark -r capture.pcap -Y 'tcp.stream == 3' -T fields \
  -e frame.number -e frame.time_relative -e ip.src -e tcp.srcport \
  -e tcp.seq -e tcp.ack -e tcp.len -e tcp.window_size

# Find candidate anomalies, then return to the full stream context.
tshark -r capture.pcap \
  -Y 'tcp.analysis.retransmission || tcp.analysis.zero_window'

IPv6 analysis should simultaneously select fields like ipv6.src. Without a handshake, negotiation information like window scaling may be unknown; blank fields may also be because the packet does not contain that layer, rather than the value being 0. TShark manual

ip.addr == A matches the address in either direction. To exclude all packets involving A, use !(ip.addr == A) to explicitly express it, avoiding intuitive derivation of inequality semantics on multi-value fields. Display filters do not re-add bytes dropped during collection. Display filters

HTTP headers may span TCP segments, and after compression or encryption, they may not be directly searchable text. tcpdump -A | grep Host: can only find visible fragments in some single packets, not a reliable HTTP request parser. Use protocol reassembly and Follow Stream, and explicitly capture whether it starts from the connection beginning.

"Retransmission" hints are analysis based on visible packets

Sequence number gaps: first distinguish path packet loss from capture missing Sender Capture point Receiver seq=1001, len=1000 seq=2001, len=1000 (not captured at this point) ACK=3001 Receiver acknowledged up to 3001; cannot directly judge missed transmission based on capture gap in the middle This is a teaching assumption; real judgment requires checking full bidirectional streams, repeated captures, sequence number wraparound, and analysis settings.
Hint or phenomenonInterpret first asContinue to verify
Previous segment not capturedGap before current visible sequence numberDid capture start midway, miss packets, or filter too narrowly?
Retransmission / Out-of-orderVisible sequence number has duplicate or out-of-order relationship with existing stream stateBidirectional ACK, timing, repeated capture, and analysis settings
ZeroWindowThis packet sender advertises zero receive windowApplication read and receive buffer status on this end
Bad checksumCurrent sampled byte calculation mismatch or insufficient verification conditionsHost-side send offloading, truncation, and capture location
"Packet" larger than usual MTUHost observed a larger processing unitIs TSO/GSO/GRO/LRO involved?

Wireshark's TCP analysis depends on the order and visible history of captured packets; its classifications can be ambiguous, and not every hint should be treated as a fact directly reported by the peer TCP implementation. TCP Analysis

Sender-side capture may occur before the NIC adds checksums or segments; receiver-side may also observe aggregated data. In this case, erroneous checksums or "large packets" do not necessarily appear on the wire. To confirm the true online form, compare receiver-side or external observation points; turning off offloading changes performance and behavior and should not be the default first step after seeing hints. Wireshark Offloading

TLS decryption requires correct session secrets, not just filling in a variable name

SSLKEYLOGFILE is a key logging interface supported by some clients and TLS libraries, not a universal switch that forces the OS to output secrets for all programs. The program must actually support it, read the configuration at startup, and produce logs matching the captured session.

Specify the log file in Wireshark's TLS protocol settings, or use offline:

tshark -r capture.pcap -o tls.keylog_file:session.keys -Y http

The decrypted protocol is not necessarily HTTP/1; HTTP/2 etc. require corresponding filters. Having only the server certificate private key cannot decrypt ECDHE sessions with forward secure exchange or typical TLS 1.3 sessions; historical RSA key exchange private key decryption has strict applicability conditions. Missing handshakes, records, or logs will also hinder reassembly and decryption. Wireshark TLS

Key logs combined with corresponding captures will expose the session content; manage access and retention scope according to the contained session data. Visible content after decryption still depends on whether the application has independent end-to-end encryption.

Offline verification of filter semantics: two SYNs and one ACK

Below generates a temporary Ethernet/IPv4/TCP pcap, reads and filters it with the installed tcpdump, without connecting to an interface or sending packets. The three packets are SYN, SYN+ECE+CWR, ACK; exact match to SYN will only match one, while the mask condition should match two.

import ipaddress
import struct
import subprocess
import tempfile
from pathlib import Path

def checksum(data):
    if len(data) % 2: data += b'\0'
    total = sum(struct.unpack('>' + 'H' * (len(data) // 2), data))
    while total >> 16: total = (total & 0xffff) + (total >> 16)
    return (~total) & 0xffff

src = ipaddress.ip_address('192.0.2.1').packed
dst = ipaddress.ip_address('192.0.2.10').packed
packets = []
for flags in [0x02, 0xc2, 0x10]:
    tcp = struct.pack('>HHIIBBHHH', 40000, 443, 1000, 0, 0x50, flags, 65535, 0, 0)
    pseudo = src + dst + struct.pack('>BBH', 0, 6, len(tcp))
    tcp = tcp[:16] + struct.pack('>H', checksum(pseudo + tcp)) + tcp[18:]
    ip = struct.pack('>BBHHHBBH4s4s', 0x45, 0, 40, 1, 0, 64, 6, 0, src, dst)
    ip = ip[:10] + struct.pack('>H', checksum(ip)) + ip[12:]
    ethernet = bytes.fromhex('0200000000020200000000010800')
    packets.append(ethernet + ip + tcp)

with tempfile.TemporaryDirectory() as folder:
    path = Path(folder) / 'flags.pcap'
    output = struct.pack('<IHHIIII', 0xa1b2c3d4, 2, 4, 0, 0, 65535, 1)
    for i, packet in enumerate(packets):
        output += struct.pack('<IIII', 1700000000 + i, 0, len(packet), len(packet))
        output += packet
    path.write_bytes(output)
    filters = [
        ('ip and tcp[tcpflags] == tcp-syn', 1),
        ('ip and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn', 2),
        ('tcp port 443', 3),
    ]
    for expression, expected in filters:
        result = subprocess.run(['tcpdump', '-nn', '-r', str(path), expression],
                                text=True, capture_output=True, check=True)
        assert len(result.stdout.strip().splitlines()) == expected
print('Offline pcap: strict SYN 1, mask SYN 2, 443 total 3')

This verifies the match between capture expressions and packet encoding, not performance testing, and does not simulate a complete TCP session. Real troubleshooting should record the original file, capture command, tool version, capture count, and key frame numbers together, so conclusions can be audited.