Routes parasites Docker : ConnMan — services injoignables depuis l'extérieur

Symptômes

<code> ip route get <IP_client_externe>

→ ... dev veth3b7619a src 169.254.x.x    # retour envoyé dans un veth Docker !

ip route show | grep -E “veth|^0.0.0.0”

0.0.0.0 dev vethXXXX scope link
default dev vethXXXX scope link          # métriques énormes (429496xxxx)
169.254.0.0/16 dev vethXXXX proto kernel scope link src 169.254.x.x

</code>

Cause racine

Quatre gestionnaires réseau cohabitaient : ifupdown (le légitime, dhclient sur enp3s0), NetworkManager (inactif sur les veth), systemd-networkd (réveillé par socket), et ConnMan — le vrai coupable.

ConnMan « adopte » chaque veth Docker à sa création, tente un DHCP dessus, échoue, retombe en IPv4LL (169.254.x) et pose des routes default/0.0.0.0 parasites qui captent le trafic retour. Identification via le journal :

<code> journalctl -b | grep -i vethXXXX

→ connmand[...]: Adding interface vethXXXX [ ethernet ]

</code>

Fausse piste initiale : systemd-networkd (fichier 10-docker-veth-unmanaged.network créé, sans effet — les veth étaient déjà unmanaged côté networkd).

Solution

Vérifier avant que ifupdown tient bien l'interface (crucial en remote) : <code> systemctl is-active networking # active ps aux | grep dhclient # dhclient … enp3s0 </code>

Puis neutraliser ConnMan avec filet de sécurité (relance auto si perte de main) : <code> # Filet : relance ConnMan dans 300 s quoi qu'il arrive systemd-run –on-active=300 systemctl start connman

# Bascule : stop ConnMan + reprise de l'interface par ifupdown systemctl stop connman; sleep 2; ifdown enp3s0; ifup enp3s0

# Si la main est conservée : annuler le filet (nom affiché par systemd-run) systemctl stop run-XXXX.timer

# Rendre permanent systemctl disable –now connman && systemctl mask connman </code>

De même pour systemd-networkd (redondant, socket-activated) : <code> systemctl disable –now systemd-networkd.socket systemd-networkd.service systemctl mask systemd-networkd.socket systemd-networkd.service </code>

Validation (après reboot)

<code> ip route show | grep -E “veth|^0.0.0.0” # vide ip route show | head -1 # default via 192.168.1.90 dev enp3s0 git fetch # depuis l'extérieur, via Gitea SSH </code>

Pièges rencontrés