Skip to content

Wire-Level Packet Analysis with tcpdump & Berkeley Packet Filters (BPF)

Created: 2026-11-08  ·  Last updated: 2026-11-08  ·  Nejat Hakan

Executive Summary: When system logs, reverse proxy error pages, and firewall metrics yield conflicting diagnoses, packets on the physical wire never lie. Built upon the Linux kernel's AF_PACKET socket family and the libpcap library, tcpdump is the premier tool for real-time packet inspection. By evaluating Berkeley Packet Filters (BPF) directly inside kernel memory, it filters gigabit streams with minimal CPU overhead, diagnoses TCP handshake anomalies, and records forensic PCAP traces for offline Wireshark analysis.

  • In-Kernel BPF Engine


    Understand how kernel-level BPF bytecode discards unwanted frames before expensive memory copies to user-space occur.

  • TCP Flag Diagnostics


    Distinguish between firewall drops, closed port resets (RST), and connection stalls by evaluating SYN, ACK, FIN, and RST bits.

  • Advanced BPF Syntax


    Construct byte-offset bitmasks to isolate TCP window scaling issues, ICMP fragmentation alerts, and specific HTTP request methods.

  • Circular PCAP Buffers


    Safely capture sporadic production bugs without exhausting server storage using size-limited circular file rotations (-C and -W).


1. The Architecture of Packet Capture: AF_PACKET & In-Kernel BPF

How does tcpdump intercept network traffic without disrupting running applications? It relies on the Linux kernel's AF_PACKET socket interface:

%%{init: {'flowchart': {'wrappingWidth': 600}}}%%
flowchart TB
    NIC["Physical NIC RX Ring"] --> DRIVER["NIC Device Driver"]
    DRIVER --> CLONE["Kernel Packet Cloner"]
    CLONE -->|"Regular Path"| STACK["TCP/IP Kernel Stack -> Application Socket"]
    CLONE -->|"Raw Copy"| BPF["In-Kernel BPF Filter Engine<br/>(Evaluates Bytecode in RAM)"]
    BPF -->|"Discard: No Match"| DROP["Dropped (0% User-Space CPU)"]
    BPF -->|"Match"| RING["AF_PACKET Ring Buffer"]
    RING -->|"sys_read() / recvfrom()"| TCPDUMP["tcpdump User-Space Process<br/>(Formats Output or Writes PCAP)"]

The Performance Imperative of In-Kernel BPF

If tcpdump copied every 10Gbps frame to user-space for string filtering, the CPU would collapse under live-lock. Instead, your BPF filter expression (e.g., 'tcp port 443') is compiled into BPF bytecode and injected directly into the kernel. The kernel executes this filter inside its interrupt/NAPI routine, discarding non-matching packets instantaneously.


2. The Golden Rule of Capture & Essential CLI Flags

The Golden Rule: ALWAYS use -nn

Never run tcpdump without -nn. Without -n, tcpdump attempts to resolve IP addresses to hostnames via reverse DNS (PTR). Without the second -n, it translates port numbers to service names (/etc/services). Resolving IPs generates immediate outbound DNS queries, which tcpdump captures, triggering a catastrophic infinite recursive loop that floods your network and freezes your terminal!

Essential CLI Flags Reference

Flag Meaning & Engineering Function
-nn Disables DNS hostname and port name resolution. Mandatory for production.
-i eth0 Specifies interface (-i any captures across all interfaces, bridges, and loopbacks).
-s 0 Sets snapshot length to 0 (captures full packet payload without truncation).
-v, -vv, -vvv Increases verbosity (prints TTL, IP IDs, TCP options, and checksums).
-X / -XX Prints payload data in both Hex and ASCII (invaluable for HTTP, DNS, and SMTP debugging).
-e Prints Layer-2 Ethernet headers (source/destination MAC addresses and 802.1Q VLAN tags).
-c 100 Exits automatically after capturing exactly 100 matching packets.
-w trace.pcap Writes raw binary packets directly to disk for analysis in Wireshark.
-r trace.pcap Reads and replays an existing PCAP capture offline.

3. Mastering Berkeley Packet Filters (BPF Syntax)

BPF filters combine Primitives, Directions, and Protocols using boolean logic (and, or, not):

1. Basic Protocol & Port Primitives

# Capture all traffic to or from host 10.10.20.11
sudo tcpdump -i eth0 -nn host 10.10.20.11

# Capture outbound HTTP/HTTPS traffic to a specific subnet
sudo tcpdump -i eth0 -nn 'dst net 198.51.100.0/24 and (port 80 or port 443)'

# Exclude noisy SSH traffic from your own management session
sudo tcpdump -i eth0 -nn 'not port 22'

2. Advanced Bitwise Flag Masking

The real power of BPF lies in bitwise operations on header bytes. The TCP flags field is located at byte offset 13 of the TCP header:

%%{init: {'flowchart': {'wrappingWidth': 600}}}%%
flowchart TB
    BYTE["TCP Header Byte 13 (Flags):<br/>[CWR | ECE | URG | ACK | PSH | RST | SYN | FIN]"]
    BYTE --> S["SYN (Bit 1): 0x02"]
    BYTE --> R["RST (Bit 2): 0x04"]
    BYTE --> F["FIN (Bit 0): 0x01"]
    BYTE --> A["ACK (Bit 4): 0x10"]
# 1. Capture only initial connection attempts (SYN without ACK)
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn'

# 2. Capture connection resets (RST) indicating dropped or refused ports
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0'

# 3. Capture IPv4 packets where the Don't Fragment (DF) bit is set
sudo tcpdump -i eth0 -nn 'ip[6] & 0x40 != 0'

4. Production Troubleshooting Recipes ("Packets Never Lie")

1. Diagnosing the TCP 3-Way Handshake

Run the following while initiating a connection with curl or a database client:

sudo tcpdump -i eth0 -nn -c 10 'tcp port 5432'

Evaluate the printed TCP flag patterns:

  • Pattern A: Healthy Open Port

    Client.49210 > Server.5432: Flags [S], seq 100234
    Server.5432 > Client.49210: Flags [S.], seq 892301, ack 100235
    Client.49210 > Server.5432: Flags [.], ack 892302
    
    Analysis: [S] (SYN) followed by [S.] (SYN-ACK) and [.] (ACK). The connection is established successfully.

  • Pattern B: Port Reached, but Service Down (Connection Refused)

    Client.49210 > Server.5432: Flags [S], seq 100234
    Server.5432 > Client.49210: Flags [R.], seq 0, ack 100235
    
    Analysis: [R.] (RST-ACK). The packet reached the destination host, but no process was listening on port 5432.

  • Pattern C: Firewall Drop (Connection Timed Out)

    Client.49210 > Server.5432: Flags [S], seq 100234
    Client.49210 > Server.5432: Flags [S], seq 100234 (Retransmission)
    
    Analysis: Repeated [S] retransmissions with zero reply from the server. The packet was dropped silently by nftables, UFW, or a cloud security group.

2. Diagnosing Broken DNS Lookups

sudo tcpdump -i any -nn -c 20 'port 53'

Inspect query IDs and response status (NXDOMAIN, SERVFAIL, or timeouts).

3. Capturing Path MTU Discovery Failures

sudo tcpdump -i any -nn 'icmp[icmptype] == icmp-unreach and icmp[icmpcode] == 4'

Detects ICMP Fragmentation Needed messages dropped by broken intermediate firewalls.


5. Circular PCAP Ringbuffers in Production

Capturing sporadic network glitches on high-throughput servers can quickly fill root partitions. Use -C (file size in MB) and -W (number of rotated files) to create a fixed-size circular ringbuffer:

# Capture full packets into /var/log/captures/
# Rotates between 5 files of 100MB each (Maximum disk consumption: 500MB)
sudo mkdir -p /var/log/captures
sudo tcpdump -i eth0 -nn -s 0 -C 100 -W 5 -w /var/log/captures/app_debug.pcap 'port 443 or port 5432'

tcpdump will create app_debug.pcap0, app_debug.pcap1, ..., and wrap around cyclically, keeping only the most recent 500MB of capture data.


6. Live Streaming Captures Directly into Wireshark

Rather than copying .pcap files back and forth with scp, stream packets directly from your remote Debian server into your local desktop Wireshark instance over an SSH pipe:

# Run on your local administrative workstation:
ssh root@203.0.113.10 "tcpdump -U -s 0 -nn -i eth0 -w - 'not port 22'" | wireshark -k -i -
  • -U: Instructs tcpdump to flush packets immediately to stdout without buffering.
  • -w -: Writes raw PCAP data to standard output.
  • wireshark -k -i -: Starts Wireshark immediately (-k) reading from standard input (-i -).

7. Where to Go Next: Cluster 3

Congratulations! You have completed Cluster 2: Security, Tunneling & Firewalls. Proceed to the architectural backbone of Linux enterprise infrastructure:

  • Cluster 3: Linux as a Layer-3 Router & NAT


    Transform Debian into an enterprise router: IP forwarding, SNAT masquerading, DNAT port forwarding, and stateful conntrack tuning.

    Layer-3 Routing Guide