42

Docker creates these virtual ethernet interfaces veth[UNIQUE ID] listed in ifconfig. How can I find out which interface belongs to a specific docker container?

I want to listen to the tcp traffic.

Mahoni
  • 7,088
  • 17
  • 58
  • 115
  • It seems like it's an open issue here https://github.com/docker/docker/issues/14666 and there are some workarounds. I'm not good at networking and I don't really understand those workarounds so I've decided to just filter by host when I use tcpdump. Works for me. Maybe will work for you if also use tcpdump or if your tool has similar filters. – Artem Malinko Jun 21 '16 at 20:00

6 Answers6

38

To locate interface
In my case getting value from container was like (check eth0 to):

$ docker exec -it my-container cat /sys/class/net/eth1/iflink
123

And then:

$ ip ad | grep 123
123: vethd3234u4@if122: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker_gwbridge state UP group default

Check with tcpdump -i vethd3234u4


Reference about mysterious iflink from http://lxr.free-electrons.com/source/Documentation/ABI/testing/sysfs-class-net:

150 What:           /sys/class/net/<iface>/iflink
151 Date:           April 2005
152 KernelVersion:  2.6.12
153 Contact:        netdev@vger.kernel.org
154 Description:
155                 Indicates the system-wide interface unique index identifier a
156                 the interface is linked to. Format is decimal. This attribute is
157                 used to resolve interfaces chaining, linking and stacking.
158                 Physical interfaces have the same 'ifindex' and 'iflink' values.
pbaranski
  • 22,778
  • 19
  • 100
  • 117
  • 1
    Does not work for me. iflink in the container is 14. "ip ad" on the host does not have interface 14. "ip ad" in the container does. Docker version 17.03.1-ce. – Curtis Yallop Jul 10 '17 at 16:42
  • I notice that interface 12 in my container happens to be interface 13 on the guest. And interface 14 in my other container is interface 15 on the guest. I tried capturing in wireshark (running on the host) and figured out which one it was based on the traffic. – Curtis Yallop Jul 10 '17 at 16:49
  • 1
    I also noticed that if in container I saw, for example 63293 and `ip addr show | grep 63293` returned me nothing, then worth to check interfaces around for 63292 and 63294. – Sysanin Mar 19 '21 at 16:16
  • Is there a way to find container's network interface that is not Linux-specific? It seems there is no /sys/class/net/eth1/iflink for us Mac users. – Nikita Rybak Apr 30 '21 at 05:49
12

Based on the provided answer (which worked for me), I made this simple bash script:

#!/bin/bash

export containers=$(sudo docker ps --format "{{.ID}}|{{.Names}}")
export interfaces=$(sudo ip ad);
for x in $containers
        do
                export name=$(echo "$x" |cut -d '|' -f 2);
                export id=$(echo "$x"|cut -d '|' -f 1)
                export ifaceNum="$(echo $(sudo docker exec -it "$id" cat /sys/class/net/eth0/iflink) | sed s/[^0-9]*//g):"
                export ifaceStr=$( echo "$interfaces" | grep $ifaceNum | cut -d ':' -f 2 | cut -d '@' -f 1);
                echo -e "$name: $ifaceStr";
done
ln -s
  • 325
  • 3
  • 12
7

My answer more like improvement on that important topic because it didn't help to "Find out which network interface belongs to docker container", but, as author noticed, he "want to listen to the tcp traffic" inside docker container - I'll try to help on that one during your troubleshooting of network.

Considering that veth network devices are about network namespaces, it is useful to know that we can execute program in another namespace via nsenter tool as follow (remember - you need a privileged permission (sudo/root) for doing that):

Get ID of any container you are interested in capture the traffic, for example it will be 78334270b8f8

Then we need to take PID of that containerized application (I assume you are running only 1 network-related process inside container and want to capture its traffic. Otherwise, that approach is hard to be suitable):

sudo docker inspect 78334270b8f8 | grep -i pid

For example, output for pid will be 111380 - that's ID of your containerized app, you can check also it via ps command: ps aux | grep 111380 just in curiosity.

Next step is to check what network interfaces you have inside your container:

sudo nsenter -t 111380 -n ifconfig

This command will return you list of network devices in network namespace of the containerized app (you should not have ifconfig tool on board of your container, only on your node/machine)

For example, you need to capture traffic on interface eth2 and filter it to tcp destination port 80 (it may vary of course) with this command:

sudo nsenter -t 111380 -n tcpdump -nni eth2 -w nginx_tcpdump_test.pcap 'tcp dst port 80'

Remember, that in this case you do not need tcpdump tool to be installed inside your container.

Then, after capturing packets, .pcap file will be available on your machine/node and to read it use any tool you prefer tcpdump -r nginx_tcpdump_test.pcap

approach's pros:

  • no need to have network tools inside container, only on docker node
  • no need to search for map between network devices in container and node

cons:

  • you need to have privileged user on node/machine to run nsenter tool
Sysanin
  • 1,501
  • 20
  • 27
  • 1
    This is the best answer because it does not rely on anything inside the container.. FYI use `docker inspect --format '{{.State.Pid}}'` instead of using grep – Dave Feb 01 '23 at 23:10
5

One-liner of the solution from @pbaranski

num=$(docker exec -i my-container cat /sys/class/net/eth0/iflink | tr -d '\r'); ip ad | grep -oE "^${num}: veth[^@]+" | awk '{print $2}'

If you need to find out on a container that does not include cat then try this tool: https://github.com/micahculpepper/dockerveth

bcoughlan
  • 25,987
  • 18
  • 90
  • 141
2

You can also read the interface names via /proc/PID/net/igmp like (container name as argument 1):

#!/bin/bash

NAME=$1
PID=$(docker inspect $NAME --format "{{.State.Pid}}")
while read iface id; do
    [[ "$iface" == lo ]] && continue
    veth=$(ip -br addr | sed -nre "s/(veth.*)@if$id.*/\1/p")
    echo -e "$NAME\t$iface\t$veth"
done < <(</proc/$PID/net/igmp awk '/^[0-9]+/{print $2 " " $1;}')
Johannes Di
  • 151
  • 1
  • 4
0

Slightly improved @ln-s' solution (cannot post as a comment hence a separate answer).

Takes into account that after connecting/disconnecting the containers to/from network, eth0 becomes eth1, eth2, and so on.

#!/bin/bash

export containers=$(sudo docker ps --format "{{.ID}}|{{.Names}}")
export interfaces=$(sudo ip ad);
for x in $containers
        do
                export name=$(echo "$x" |cut -d '|' -f 2);
                export id=$(echo "$x"|cut -d '|' -f 1)
                export ethNum="$(echo $(sudo docker exec -it "$id" ls /sys/class/net) | grep -oP 'eth[0-9]')"
                export ifaceNum="$(echo $(sudo docker exec -it "$id" cat /sys/class/net/$ethNum/iflink) | sed s/[^0-9]*//g):"
                export ifaceStr=$( echo "$interfaces" | grep $ifaceNum | cut -d ':' -f 2 | cut -d '@' -f 1);
                echo -e "$name: $ifaceStr";
done
eexaxa
  • 37
  • 4