Routes parasites Docker : ConnMan — services injoignables depuis l'extérieur
Symptômes
- Gitea SSH (port 8329) injoignable depuis le WAN, web OK. Précédemment : NFS via WireGuard en timeout.
tcpdumpcôté serveur : SYN reçus, aucun SYN-ACK renvoyé — le retour part dans le vide.- Symptôme générique : tout trafic retour vers une destination hors LAN (IP publiques, réseau VPN) est détourné.
<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
systemctl stop connmanà chaud sans ifup derrière : ConnMan flushe l'IP deenp3s0en mourant → serveur injoignable (reset électrique nécessaire).- Les routes parasites déjà posées ne partent pas seules :
ip route flush dev vethXXXX. - Attention au flush : il peut aussi emporter la route par défaut si elle avait été posée par le gestionnaire fautif → vérifier
ip route showjuste après.
