Utiliser TcpDump avec Docker
A partir de Docker
Construction de l’image Docker
Construction de l’image Docker en utilisant le Here Document
docker build -t tcpdump - <<EOF
FROM ubuntu
RUN apt-get update && apt-get install -y tcpdump
CMD tcpdump -i eth0
EOF
Ce qui nous créé une images avec la commane tcpdump
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tcpdump latest 9cc11b561802 7 seconds ago 123MB
Utilisation de l’image Tcpdump
L’idée est de pouvoir analyser la communication entre plusieurs containers, par exemple le traffic entre les gateways wireguard
. Il est possible de lancer un container qui s’accroche au réseau d’un autre container avec l’option --network=container:<container_name>
# docker ps
1CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
254343975be23 masipcat/wireguard-go:latest "/entrypoint.sh" 15 minutes ago Up 15 minutes GW_CL1
3b9d22ebbc6c2 masipcat/wireguard-go:latest "/entrypoint.sh" 15 minutes ago Up 15 minutes GW_CL2
407f1e4236644 lscr.io/linuxserver/openssh-server:latest "/init" 15 minutes ago Up 15 minutes server_1
589958c26c546 lscr.io/linuxserver/openssh-server:latest "/init" 15 minutes ago Up 15 minutes server_3
65ddec96e70aa masipcat/wireguard-go:latest "/entrypoint.sh" 15 minutes ago Up 15 minutes GW_PRES
70c91a8bf2fea lscr.io/linuxserver/openssh-server:latest "/init" 15 minutes ago Up 15 minutes server_2
On lance le container TCPDUMP
sur le réseau cible
docker run --tty --rm --net=container:GW_PRES tcpdump
On obtient ceci:
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
18:37:31.969196 IP GW_PRES.51820 > GW_CL1.ext_net.51820: UDP, length 32
18:37:32.634443 IP GW_CL2.ext_net.51820 > GW_PRES.51820: UDP, length 32
18:37:36.969316 IP GW_PRES.51820 > GW_CL1.ext_net.51820: UDP, length 32
18:37:36.969439 IP GW_CL1.ext_net.51820 > GW_PRES.51820: UDP, length 32
18:37:37.634630 IP GW_CL2.ext_net.51820 > GW_PRES.51820: UDP, length 32
18:37:41.969612 IP GW_PRES.51820 > GW_CL1.ext_net.51820: UDP, length 32
18:37:41.969626 IP GW_CL1.ext_net.51820 > GW_PRES.51820: UDP, length 32
18:37:41.992623 ARP, Request who-has GW_CL1.ext_net tell GW_PRES, length 28
18:37:41.992922 ARP, Request who-has GW_PRES tell GW_CL1.ext_net, length 28
18:37:41.992926 ARP, Reply GW_PRES is-at 02:42:0a:0a:00:05 (oui Unknown), length 28
18:37:41.992932 ARP, Reply GW_CL1.ext_net is-at 02:42:0a:14:00:05 (oui Unknown), length 28
18:37:42.634807 IP GW_PRES.51820 > GW_CL2.ext_net.51820: UDP, length 32
18:37:42.634824 IP GW_CL2.ext_net.51820 > GW_PRES.51820: UDP, length 32
On voit que la commande attachée à notre container espion sur l’interface eth0
de notre container GW_PRES
# docker exec -it GW_PRES ifconfig -a
On voit s’aperçoit que notre container possède plusieurs interfaces réseaux
eth0 Link encap:Ethernet HWaddr 02:42:0A:0A:00:05
inet addr:10.10.0.5 Bcast:10.255.255.255 Mask:255.0.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1231 errors:0 dropped:0 overruns:0 frame:0
TX packets:1246 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:86390 (84.3 KiB) TX bytes:87484 (85.4 KiB)
eth1 Link encap:Ethernet HWaddr 02:42:C0:A8:0A:01
inet addr:192.168.10.1 Bcast:192.168.10.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:17 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:1318 (1.2 KiB) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:4 errors:0 dropped:0 overruns:0 frame:0
TX packets:4 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1
RX bytes:372 (372.0 B) TX bytes:372 (372.0 B)
wg0 Link encap:UNSPEC HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00
inet addr:10.10.0.5 P-t-P:10.10.0.5 Mask:255.255.255.255
UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1420 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
On veut s’avoir ce qui se passe sur le réseau interne de ce container.
# docker run --tty --net=container:GW_PRES tcpdump tcpdump -i eth1
- Le premier
Tcpdump
est le nom de l’image docker - Le second
Tcpdump
est la commande a exécuter dans le container en bypassant la commandeCMD
par défaut avec les options suivantes:- -N - N’inclue pas le domaine, ici
ipsec_int_h1
-i eth1
- utilise l’interfaceeth1
du container (réseau interne)
- -N - N’inclue pas le domaine, ici
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
19:15:49.540999 IP GW_PRES > server_1: ICMP echo request, id 19712, seq 0, length 64
19:15:49.541042 IP server_1 > GW_PRES: ICMP echo reply, id 19712, seq 0, length 64
19:15:50.541181 IP GW_PRES > server_1: ICMP echo request, id 19712, seq 1, length 64
19:15:50.541209 IP server_1 > GW_PRES: ICMP echo reply, id 19712, seq 1, length 64
19:15:51.541343 IP GW_PRES > server_1: ICMP echo request, id 19712, seq 2, length 64
19:15:51.541372 IP server_1 > GW_PRES: ICMP echo reply, id 19712, seq 2, length 64
19:15:52.541590 IP GW_PRES > server_1: ICMP echo request, id 19712, seq 3, length 64
19:15:52.541620 IP server_1 > GW_PRES: ICMP echo reply, id 19712, seq 3, length 64
19:15:54.724558 ARP, Request who-has server_1 tell GW_PRES, length 28
19:15:54.724574 ARP, Request who-has GW_PRES tell server_1, length 28
19:15:54.724578 ARP, Reply GW_PRES is-at 02:42:c0:a8:0a:01 (oui Unknown), length 28
19:15:54.724583 ARP, Reply server_1 is-at 02:42:c0:a8:0a:64 (oui Unknown), length 28
On peut trés bien décider de regrder ce qui se passe sur l’interface wg0
, tunnel ipsec wireguard
docker run --tty --net=container:GW_PRES tcpdump tcpdump -N -i wg0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on wg0, link-type RAW (Raw IP), snapshot length 262144 bytes
19:17:46.913521 IP GW_PRES > 192.168.20.100: ICMP echo request, id 20224, seq 0, length 64
19:17:47.913906 IP GW_PRES > 192.168.20.100: ICMP echo request, id 20224, seq 1, length 64
19:17:48.914043 IP GW_PRES > 192.168.20.100: ICMP echo request, id 20224, seq 2, length 64
19:17:49.914173 IP GW_PRES > 192.168.20.100: ICMP echo request, id 20224, seq 3, length 64
19:17:50.914309 IP GW_PRES > 192.168.20.100: ICMP echo request, id 20224, seq 4, length 64
19:17:51.914359 IP GW_PRES > 192.168.20.100: ICMP echo request, id 20224, seq 5, length 64
19:17:56.260821 IP GW_PRES > 192.168.30.100: ICMP echo request, id 20480, seq 0, length 64
19:17:57.260964 IP GW_PRES > 192.168.30.100: ICMP echo request, id 20480, seq 1, length 64
19:17:58.261191 IP GW_PRES > 192.168.30.100: ICMP echo request, id 20480, seq 2, length 64
19:17:59.261326 IP GW_PRES > 192.168.30.100: ICMP echo request, id 20480, seq 3, length 64
19:18:00.261391 IP GW_PRES > 192.168.30.100: ICMP echo request, id 20480, seq 4, length 64
19:18:01.261620 IP GW_PRES > 192.168.30.100: ICMP echo request, id 20480, seq 5, length 64
Sur l’hôte docker
# iptables --list -t nat
# Warning: iptables-legacy tables present, use iptables-legacy to see them
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER all -- anywhere anywhere ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER all -- anywhere !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 10.0.0.0/8 anywhere
MASQUERADE all -- 172.17.0.0/16 anywhere
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- anywhere anywhere
RETURN all -- anywhere anywhere
A partir du serveur Docker
Utilisation de la commande TCPDUMP sur l’hôte docker
Tout d’abord, on récupére le pid du conteneur qui nous intéresse.
On peux soit utiliser son CONTAINER_ID
, soit son DOCKER_NAME
docker inspect --format "{{ .State.Pid }}" "$CONTAINER_ID"
On se positionne dans le même espace de noms réseau
nsenter -n -t "$PID"
Il ne reste plus qu’a lancer tcpdump. Pour sortir de l’espace de nom, un ‘Ctrl+d’