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
Tcpdumpest le nom de l’image docker - Le second
Tcpdumpest la commande a exécuter dans le container en bypassant la commandeCMDpar défaut avec les options suivantes:- -N - N’inclue pas le domaine, ici
ipsec_int_h1 -i eth1- utilise l’interfaceeth1du 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’
