Packet Capture on VyOS: tcpdump Techniques for Real Debugging

Logs say everything is fine. Routing table looks correct. Firewall rules seem right. But traffic still doesn’t flow. What’s actually happening?

Packet capture shows you the truth. The actual packets. Not what the logs say happened, not what should happen according to config — what actually happens on the wire.

Packets never lie.

Basic Packet Capture

VyOS Monitor Traffic Command

Terminal window
# VyOS provides a wrapper around tcpdump
monitor traffic interface eth0
# Stop with Ctrl+C

Direct tcpdump

Terminal window
# More control with tcpdump directly
sudo tcpdump -i eth0
# Common options
sudo tcpdump -i eth0 -n # Don't resolve names (faster)
sudo tcpdump -i eth0 -v # Verbose
sudo tcpdump -i eth0 -vv # More verbose
sudo tcpdump -i eth0 -c 100 # Capture 100 packets then stop

Capture Filters

By IP Address

Terminal window
# Traffic from specific source
sudo tcpdump -i eth0 -n src 192.168.1.100
# Traffic to specific destination
sudo tcpdump -i eth0 -n dst 8.8.8.8
# Traffic to or from host
sudo tcpdump -i eth0 -n host 192.168.1.100
# Traffic between two hosts
sudo tcpdump -i eth0 -n host 192.168.1.100 and host 8.8.8.8

By Network

Terminal window
# Traffic to/from subnet
sudo tcpdump -i eth0 -n net 192.168.1.0/24
# Traffic NOT from subnet
sudo tcpdump -i eth0 -n not net 192.168.1.0/24

By Protocol

Terminal window
# ICMP only
sudo tcpdump -i eth0 -n icmp
# TCP only
sudo tcpdump -i eth0 -n tcp
# UDP only
sudo tcpdump -i eth0 -n udp
# ARP
sudo tcpdump -i eth0 -n arp
# OSPF
sudo tcpdump -i eth0 -n proto ospf
# BGP (TCP 179)
sudo tcpdump -i eth0 -n tcp port 179

By Port

Terminal window
# Specific port
sudo tcpdump -i eth0 -n port 80
sudo tcpdump -i eth0 -n port 443
# Source port
sudo tcpdump -i eth0 -n src port 22
# Destination port
sudo tcpdump -i eth0 -n dst port 80
# Port range
sudo tcpdump -i eth0 -n portrange 1-1024

Combined Filters

Terminal window
# HTTP traffic from specific host
sudo tcpdump -i eth0 -n host 192.168.1.100 and port 80
# SSH excluding specific host
sudo tcpdump -i eth0 -n port 22 and not host 192.168.1.1
# All traffic except SSH (while connected via SSH)
sudo tcpdump -i eth0 -n not port 22
# TCP SYN packets (new connections)
sudo tcpdump -i eth0 -n 'tcp[tcpflags] & (tcp-syn) != 0'
# TCP RST packets (connection resets)
sudo tcpdump -i eth0 -n 'tcp[tcpflags] & (tcp-rst) != 0'

Saving Captures

Write to File

Terminal window
# Save to pcap file
sudo tcpdump -i eth0 -n -w /tmp/capture.pcap
# Save with rotation (10 files of 100MB each)
sudo tcpdump -i eth0 -n -w /tmp/capture.pcap -C 100 -W 10
# Save with timestamp in filename
sudo tcpdump -i eth0 -n -w /tmp/capture-$(date +%Y%m%d-%H%M%S).pcap

Read from File

Terminal window
# Read saved capture
sudo tcpdump -r /tmp/capture.pcap
# Read with filter
sudo tcpdump -r /tmp/capture.pcap tcp port 80
# Transfer to workstation for Wireshark analysis
scp admin@router:/tmp/capture.pcap .

Capture Strategies

Strategy 1: Two-Point Capture

Capture at both ends to see what’s happening:

Terminal window
# On router ingress
sudo tcpdump -i eth0 -n host 192.168.1.100 -w /tmp/ingress.pcap
# On router egress
sudo tcpdump -i eth1 -n host 192.168.1.100 -w /tmp/egress.pcap
# Compare: Did packet arrive? Did it leave?

Strategy 2: All-Interface Capture

Terminal window
# Capture on all interfaces
sudo tcpdump -i any -n host 192.168.1.100
# Shows which interface packets traverse
# Note: May see packet twice (in and out)

Strategy 3: Before/After NAT

Terminal window
# Inside interface (pre-NAT source IP)
sudo tcpdump -i eth1 -n src 192.168.1.100
# Outside interface (post-NAT source IP)
sudo tcpdump -i eth0 -n src <public-ip>
# Verify NAT translation is happening

Strategy 4: Firewall Debug

Terminal window
# Capture traffic that should be allowed
sudo tcpdump -i eth0 -n dst port 443 and dst 192.168.1.100
# If packets arrive but connection fails:
# - Firewall blocking
# - No return route
# - Server not listening

Reading tcpdump Output

TCP Three-Way Handshake

Terminal window
# Normal connection:
10:15:01 IP 192.168.1.100.54321 > 8.8.8.8.80: Flags [S], seq 1000
10:15:01 IP 8.8.8.8.80 > 192.168.1.100.54321: Flags [S.], seq 2000, ack 1001
10:15:01 IP 192.168.1.100.54321 > 8.8.8.8.80: Flags [.], ack 2001
# [S] = SYN
# [S.] = SYN-ACK
# [.] = ACK
# [P.] = PUSH-ACK (data)
# [F.] = FIN-ACK
# [R.] = RST-ACK

Connection Refused

Terminal window
# RST immediately after SYN
10:15:01 IP 192.168.1.100.54321 > 8.8.8.8.80: Flags [S], seq 1000
10:15:01 IP 8.8.8.8.80 > 192.168.1.100.54321: Flags [R.], ack 1001
# Means: Port closed or filtered

Connection Timeout

Terminal window
# SYN retransmits, no response
10:15:01 IP 192.168.1.100.54321 > 8.8.8.8.80: Flags [S], seq 1000
10:15:02 IP 192.168.1.100.54321 > 8.8.8.8.80: Flags [S], seq 1000
10:15:04 IP 192.168.1.100.54321 > 8.8.8.8.80: Flags [S], seq 1000
# Means: Packets not reaching destination or response not returning

Protocol-Specific Captures

DNS Debugging

Terminal window
# Capture DNS queries and responses
sudo tcpdump -i eth0 -n port 53
# Verbose to see query details
sudo tcpdump -i eth0 -n -v port 53
# Example output:
# 192.168.1.100.12345 > 8.8.8.8.53: 12345+ A? example.com.
# 8.8.8.8.53 > 192.168.1.100.12345: 12345 1/0/0 A 93.184.216.34

HTTP Debugging

Terminal window
# Capture HTTP traffic
sudo tcpdump -i eth0 -n -A port 80
# -A shows ASCII content (HTTP headers)
# WARNING: May capture sensitive data

BGP Session

Terminal window
# Capture BGP traffic
sudo tcpdump -i eth0 -n tcp port 179
# See BGP OPEN, UPDATE, KEEPALIVE messages
sudo tcpdump -i eth0 -n -v tcp port 179

OSPF

Terminal window
# Capture OSPF traffic
sudo tcpdump -i eth0 -n proto ospf
# See Hello, LSA, DBD packets

IPsec

Terminal window
# Capture IKE negotiation (UDP 500/4500)
sudo tcpdump -i eth0 -n udp port 500 or udp port 4500
# Capture ESP packets
sudo tcpdump -i eth0 -n proto esp

Common Troubleshooting Scenarios

Scenario 1: Traffic Not Reaching Destination

Terminal window
# Step 1: Capture at source
sudo tcpdump -i eth1 -n src 192.168.1.100 and dst 8.8.8.8
# Step 2: Capture at exit interface
sudo tcpdump -i eth0 -n src 192.168.1.100 and dst 8.8.8.8
# (use NAT source if applicable)
# If packets on eth1 but not eth0:
# - Firewall blocking
# - Routing issue

Scenario 2: Asymmetric Routing

Terminal window
# Capture on both interfaces
sudo tcpdump -i eth0 -n host 192.168.1.100
sudo tcpdump -i eth1 -n host 192.168.1.100
# If request on eth0, response on eth1:
# - Asymmetric routing
# - Might be dropped by stateful firewall

Scenario 3: Connection Resets

Terminal window
# Find who sends RST
sudo tcpdump -i eth0 -n 'tcp[tcpflags] & (tcp-rst) != 0'
# If RST from destination: Port closed or application error
# If RST from middle: Firewall, IPS, or timeout

Scenario 4: MTU Problems

Terminal window
# Look for fragmentation
sudo tcpdump -i eth0 -n 'ip[6:2] & 0x1fff != 0'
# Look for ICMP fragmentation needed
sudo tcpdump -i eth0 -n 'icmp[0] = 3 and icmp[1] = 4'
# If you see these, MTU/MSS issue

Advanced Techniques

Capture Only Headers

Terminal window
# Capture only first 96 bytes (headers)
sudo tcpdump -i eth0 -n -s 96 -w /tmp/headers-only.pcap
# Reduces file size, still useful for analysis

Ring Buffer for Continuous Capture

Terminal window
# Keep last 100MB of traffic
sudo tcpdump -i eth0 -n -w /tmp/capture.pcap -C 10 -W 10
# 10 files × 10MB = 100MB rotating buffer
# Useful for catching intermittent issues

Trigger-Based Capture

/config/scripts/triggered-capture.sh
#!/bin/bash
# Start capture when problem detected
while true; do
# Check for symptom (e.g., high conntrack)
if [ $(cat /proc/sys/net/netfilter/nf_conntrack_count) -gt 50000 ]; then
timeout 60 tcpdump -i eth0 -n -w /tmp/triggered-$(date +%s).pcap
fi
sleep 10
done

Best Practices

1. Filter Early

Terminal window
# Bad: Capture everything, filter later
sudo tcpdump -i eth0 -w /tmp/huge.pcap
# Good: Filter during capture
sudo tcpdump -i eth0 -n host 192.168.1.100 and port 80 -w /tmp/small.pcap

2. Exclude SSH (When Connected via SSH)

Terminal window
# Avoid capturing your own session
sudo tcpdump -i eth0 -n not port 22

3. Use Names for Saved Files

Terminal window
# Include date, interface, purpose
sudo tcpdump -i eth0 -n host 192.168.1.100 \
-w /tmp/eth0-192.168.1.100-$(date +%Y%m%d-%H%M%S).pcap

4. Know When to Stop

Terminal window
# Set packet count limit
sudo tcpdump -i eth0 -n -c 1000 -w /tmp/capture.pcap
# Set time limit
timeout 60 sudo tcpdump -i eth0 -n -w /tmp/capture.pcap

The Lesson

Packets never lie.

When troubleshooting fails with logs and commands, packet capture shows exactly what’s happening:

  • Is the traffic arriving?
  • Is it leaving?
  • Is the firewall changing it?
  • Is NAT translating it?
  • Is the destination responding?

The capture tells you what logs cannot: the actual bytes on the wire.

Every network engineer should be comfortable with tcpdump. Not Wireshark on a desktop — tcpdump on the router where the problem is.

Start simple: tcpdump -i eth0 -n host problem-ip. Build filters from there. Save captures for complex analysis. But start by looking at the packets.

They never lie.