Skip to main content
RunBook Academy

OPNsenseXXXVI · Packet Capture and Diagnosticstcpdump on the firewall

tcpdump on the firewall — the operator's primary capture tool

Intermediate⏱ ~13 mintcpdumppfctlngrep

What you'll learn

  • Construct tcpdump commands for common troubleshooting questions
  • Use BPF filters to limit capture to the relevant traffic
  • Rotate captures to avoid filling the filesystem
  • Read tcpdump output quickly and accurately

Prerequisites

Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-14

Not yet marked complete on this device.

The graphical live capture page is convenient for a quick look. The operator who needs to capture into a file, run for hours, or apply precise filters uses tcpdump from the shell. OPNsense’s console menu, SSH session, and diagnostic shell all provide access to tcpdump with the same arguments any other FreeBSD host would use.

This lesson covers the tcpdump flags the operator needs every day, the BPF filter expressions that limit capture to the relevant slice, the rotation pattern that prevents the filesystem from filling, and the discipline of reading the output.

The minimum tcpdump invocation

The most useful tcpdump form is small and consistent:

tcpdump -ni <interface> <bpf-filter>
  • -n — disable DNS and service-name resolution. The output prints raw IP addresses and port numbers. The operator can decide to add -N for partial name resolution later if needed.
  • -i <iface> — the interface to capture on. OPNsense uses driver names: igb0, ix0, vtnet0, em0, plus VLAN interfaces like igb0_vlan10.
  • BPF filter — optional but recommended. Without a filter, tcpdump captures every frame on the interface, which on a busy link overwhelms both the buffer and the operator.
Read-only / Safetcpdump filtered by host and port
$ tcpdump -ni igb0 host 192.0.2.50 and port 443
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on igb0, link-type EN10MB (Ethernet), capture size 262144 bytes
12:34:56.789012 aa:bb:cc:11:22:33 > 66:77:88:99:aa:bb, IPv4, length 74: 192.0.2.50.51820 > 203.0.113.5.443: Flags [S], seq 1234567890, win 65535, options [mss 1460,sackOK,ts val 1234567 ecr 0,nop,wscale 7], length 0

Illustrative output

Useful flags

The flags the operator uses most often:

  • -e — print the link-level header (source and destination MAC).
  • -v, -vv, -vvv — increase verbosity. -v adds the TTL, IP ID, total length, IP options, and decodes more protocols. -vv adds NFS and SMB details. -vvv is rarely needed.
  • -c N — stop after N packets.
  • -w file.pcap — write raw packets to a file in pcap format. The file can be opened in Wireshark later.
  • -r file.pcap — read packets from a pcap file instead of an interface. Useful for post-mortem analysis.
  • -s snaplen — set the snapshot length (per-packet byte cap). Default on FreeBSD is typically 262144 bytes (full packet); the legacy default of 68 or 96 is rarely what the operator wants.
  • -ttt — print delta from previous packet.
  • -tttt — print absolute timestamp with date.
Read-only / Safetcpdump arp with link header
$ tcpdump -ni igb0 -e -c 1 arp
12:34:56.789012 aa:bb:cc:11:22:33 > ff:ff:ff:ff:ff:ff, ARP, Request who-has 192.0.2.1 tell 192.0.2.50, length 28

Illustrative output

Writing to a file and rotating

Long-running captures must write to a file (the terminal cannot display hours of traffic) and must rotate (a single huge file is hard to analyse and fills the disk). The pattern:

tcpdump -ni igb0 -w /root/capture.pcap -G 3600 -W 24 host 192.0.2.50
  • -w file.pcap — write to file.
  • -G seconds — rotate the file every N seconds.
  • -W count — keep at most N rotated files. Older files are overwritten.

In this example, files rotate every hour (-G 3600) and the last 24 are kept (-W 24). After 24 hours the oldest file is overwritten. The operator has a 24-hour window of captures at any moment.

A capture workflow

A typical capture session for “is the firewall forwarding traffic from host A to host B”:

  1. Identify the interfaces. Source: the interface host A is on. Destination: the interface host B is on.
  2. Write a precise filter. host A-IP and host B-IP is a starting point; the operator narrows by port, protocol, or direction as the question sharpens.
  3. Capture for a bounded time. -c N if the operator knows roughly how many packets to expect; -G 60 if the operator needs at least one minute regardless.
  4. Trigger the traffic. Have host A start the flow while the capture is running.
  5. Stop, then analyse. Ctrl-C the capture; read with tcpdump -r or open the pcap in Wireshark.
Read-only / Safetcpdump bounded capture
$ tcpdump -ni igb0 -w /tmp/forward-test.pcap -c 100 'host 192.0.2.50 and 203.0.113.5'
tcpdump: listening on igb0, link-type EN10MB (Ethernet), capture size 262144 bytes
100 packets captured
102 packets received by filter
0 packets dropped by kernel

Illustrative output

Common BPF patterns

The BPF expressions the operator reaches for most often:

QuestionFilter
Traffic to/from one hosthost 192.0.2.50
Traffic to/from one networknet 192.0.2.0/24
Traffic to a specific portport 443
Traffic between two hostshost 192.0.2.50 and host 203.0.113.5
All TCP traffictcp
All UDP trafficudp
ICMP onlyicmp
ARP onlyarp
Exclude a noisy hostnot host 192.0.2.100
TCP SYN only (connection starts)tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack == 0
DNS trafficport 53

The expressions can be combined with and, or, not, and parentheses.

Reading the output

The operator must read tcpdump output quickly. The fields in order:

  1. Timestamp — when libpcap read the frame.
  2. Source > destination (link layer) — only with -e. MAC addresses.
  3. Network layerIPv4, IPv6, ARP, etc.
  4. Length — total frame length on the wire.
  5. Source IP.port > destination IP.port — IP and transport endpoints.
  6. Protocol-specific details — TCP flags, sequence/ack, ICMP type/code, etc.
  7. Length — payload length.

For TCP, the operator reads:

  • Flags [S] — SYN, connection start.
  • Flags [S.] — SYN-ACK, the server’s response.
  • Flags [.] — ACK with no other flag — a data packet.
  • Flags [F.] — FIN, clean close.
  • Flags [R] — RST, abort.
  • Flags [P.] — PSH-ACK, data with push.

The discipline is to recognise the TCP state from the flags: a flow with [S], [S.], [.], [.], [F.], [F.] is a normal connection. A flow with [S], [R] is a refused connection — the server responded with RST.

Summary

  • The minimum tcpdump form is tcpdump -ni <iface> <filter>; the operator should always pass -n to disable name resolution.
  • Capture to a file with rotation (-G and -W) for any capture longer than a minute; never capture to stdout for extended periods.
  • A capture session is a hypothesis test: write a filter, trigger the traffic, capture, analyse.
  • TCP flags identify the connection state: [S] is SYN, [S.] is SYN-ACK, [.] is data, [F.] is FIN, [R] is RST.
  • The summary line of a bounded capture is critical: “0 packets dropped by kernel” is the canary for capture completeness.

Knowledge check · 4 questions

  1. Q1. You start a tcpdump capture with `-c 100` and the summary line at the end shows "100 packets captured, 102 packets received by filter, 0 packets dropped by kernel". What does this tell you?

  2. Q2. Capturing for hours to stdout (the terminal) is an acceptable practice if the operator can scroll back far enough.

  3. Q3. Which BPF filter expressions would capture TCP SYN packets (only SYN, no ACK)? Select all that apply.

  4. Q4. You want to capture only ARP traffic on the LAN interface and see the source and destination MAC addresses. Which command?

Passing score: 75%. Answers are checked in this browser.