A detached veth pair is the most common reason tcpdump within a Linux container fails to see traffic it should.

This happens because a veth pair, by design, has two ends. One end lives in the container’s network namespace, and the other lives in the host’s network namespace. When you run tcpdump inside the container, it only sees the network interfaces within that container’s namespace. If the other end of the veth pair—the one on the host—isn’t correctly attached to a bridge or another interface that tcpdump on the host can see, then the traffic flowing through that veth pair will be "lost" from the perspective of the container’s tcpdump. It’s not lost from the system’s perspective, just from the specific namespace you’re looking in.

Here’s a breakdown of common causes and how to fix them:

1. The Host-Side veth is Not Connected to a Bridge

Diagnosis: On the host, run ip link show. Look for the veth interface that corresponds to your container. It will likely have a name like vethxxxxxx. Then, run brctl show. If this vethxxxxxx interface is not listed under the interfaces column for any bridge (e.g., docker0, cbr0), this is your problem.

Fix: You need to attach the host-side veth to the bridge your container is supposed to be on. This is often handled automatically by container runtimes like Docker, but manual intervention might be needed if things are set up unconventionally.

Let’s say your container’s veth interface on the host is veth123456 and the bridge is docker0. On the host:

sudo brctl addif docker0 veth123456

This command adds the veth123456 interface as a port to the docker0 bridge.

Why it works: Bridges act like virtual switches. By adding the veth’s host-side end to a bridge, you’re connecting it to the network that other interfaces (like the bridge’s own IP address, or other containers attached to the same bridge) can communicate with. Now, traffic entering the bridge from any port can be forwarded to other ports, including the container’s veth end.

2. Incorrect Network Namespace for tcpdump

Diagnosis: You might be running tcpdump in the wrong namespace. If you’re trying to capture traffic for a specific container, you need to run tcpdump within that container’s network namespace. On the host, you can check which namespace a process is in using ps -ef | grep <pid>. The net column will show the namespace ID.

Fix:

Use the nsenter command to enter the correct network namespace before running tcpdump. First, find the PID of a process inside the target container (e.g., docker inspect <container_name> --format '{{.State.Pid}}'). Then, on the host:

sudo nsenter -t <container_pid> -n tcpdump -i eth0 -nn

Replace <container_pid> with the actual PID of a process in your container, and eth0 with the interface name inside the container (usually eth0 or eth1).

Why it works: nsenter -t <container_pid> -n temporarily places your command into the network namespace of the process with <container_pid>. This makes the tcpdump command see the network stack as if it were running inside the container, thus seeing the container’s interfaces.

3. Interface Name Mismatch

Diagnosis: Inside the container, the network interface might not be named eth0. It could be eth1, or something else entirely. Running tcpdump -i eth0 will silently fail to capture anything if eth0 doesn’t exist.

Fix: First, list interfaces inside the container:

sudo docker exec <container_name> ip link show

Identify the correct interface name (e.g., eth1). Then, run tcpdump using that name:

sudo docker exec <container_name> tcpdump -i eth1 -nn

Or, if using nsenter:

sudo nsenter -t <container_pid> -n tcpdump -i eth1 -nn

Why it works: tcpdump needs to be told which interface to listen on. Specifying the correct, existing interface name ensures it targets the right network traffic.

4. Container Network Mode is host

Diagnosis: If the container is running in --network host mode, it shares the host’s network namespace. This means tcpdump inside the container will see all of the host’s interfaces, but it won’t be capturing traffic specific to the container’s isolated network stack (because there isn’t one).

Fix: If you need to capture traffic for a container running in host mode, you must run tcpdump on the host itself. You can then filter by the process ID of the container if needed, or by destination/source IP addresses that you know belong to the container.

On the host:

sudo tcpdump -i any -nn host <container_ip_address>

Replace <container_ip_address> with the IP address the container is using on the host.

Why it works: In host mode, the container is the host from a networking perspective. Any network capture on the host will see the container’s traffic, as it’s indistinguishable from other host traffic.

5. Firewall Rules Blocking Traffic

Diagnosis: Although less common for veth interfaces themselves, firewall rules (like iptables on the host) could be inadvertently dropping or rejecting traffic destined for or originating from the container’s veth interface before tcpdump can see it.

Fix: Temporarily disable or inspect firewall rules on the host. On the host:

sudo iptables -L -v -n

Look for rules in FORWARD or INPUT/OUTPUT chains that might be affecting the container’s IP or the veth interface. You might need to adjust or remove specific rules. For example, to allow traffic on the docker0 bridge:

sudo iptables -I FORWARD -i docker0 -o docker0 -j ACCEPT

(Note: This is a simplified example; actual firewall configurations can be complex.)

Why it works: Firewalls are designed to permit or deny network packets. If a rule is misconfigured, it can block traffic that should be flowing, making it invisible to capture tools. Allowing the traffic explicitly permits it to pass.

6. tcpdump Not Installed in the Container

Diagnosis: The most basic check: is tcpdump even installed in the container?

sudo docker exec <container_name> which tcpdump

If this returns nothing or an error, it’s not installed.

Fix: Install tcpdump inside the container. This depends on the container’s base image. For Debian/Ubuntu-based images:

sudo docker exec <container_name> apt-get update && sudo docker exec <container_name> apt-get install -y tcpdump

For Alpine-based images:

sudo docker exec <container_name> apk update && sudo docker exec <container_name> apk add tcpdump

Why it works: You can’t run a command that doesn’t exist. Installing tcpdump makes it available for use.

After addressing these, the next error you might encounter is Permission denied if tcpdump is run by a non-root user inside the container, requiring the CAP_NET_RAW capability or running as root.

Want structured learning?

Take the full Tcpdump course →