Aller au contenu
Sylvain Joffraud l4w
Retour

Deux VPN sur le même /24 : le full-tunnel éclipse ton mesh

Un git push vers un Gitea self-hosted accessible uniquement par le mesh WireGuard, et soudain : timeout. Le mesh « marchait » pourtant cinq minutes plus tôt. ping 10.8.0.1 répondait, à 20 ms. Mais les ports du serveur (Gitea, MinIO) étaient tous « filtrés ». Le coupable n’était pas le pare-feu : c’était la table de routage.

Le symptôme trompeur

$ ping -c1 10.8.0.1
64 bytes from 10.8.0.1: ... time=20.9 ms      # repond, l'air OK
$ git ls-remote origin                         # → hang puis timeout
$ for p in 222 3000 9100; do nc -zw3 10.8.0.1 $p; done
port 222: FILTERED ; 3000: FILTERED ; 9100: FILTERED

Le réflexe naturel : « le service est tombé », ou « le pare-feu bloque ». Les deux étaient faux — côté serveur, tout écoutait, le conteneur tournait depuis des semaines.

La vraie cause : collision de sous-réseau

$ ip route get 10.8.0.1
10.8.0.1 dev tun0 src 10.8.0.17 ...

tun0, pas wg0. Un second VPN (OpenVPN, pro) s’était connecté entre-temps, en full-tunnel (default via 10.8.0.1 dev tun0), et il utilisait le même plan d’adressage 10.8.0.0/24 que mon mesh WireGuard. Résultat : 10.8.0.1 ne désignait plus la gateway du mesh, mais celle de l’autre VPN — qui répond au ping (c’est une vraie gateway) mais n’héberge évidemment ni mon Gitea ni mon MinIO.

Le 10.8.0.1 qui répondait au ping et le 10.8.0.1 que je voulais joindre étaient deux machines différentes. Le ping ne ment pas — il dit juste à qui il parle, et ce n’était pas le bon.

Deux réseaux privés sur le même /24, et celui dont la route est la plus spécifique (ou le full-tunnel arrivé en dernier) gagne. Le mesh n’était pas cassé : il était éclipsé.

Le correctif (et le vrai correctif)

Immédiat : couper l’OpenVPN, relancer WireGuard, vérifier que la route repointe :

$ nmcli con down vpn-pro && nmcli con up wg-mesh
$ ip route get 10.8.0.1
10.8.0.1 dev wg-mesh src 10.8.0.2 ...           # à nouveau le mesh

Le vrai correctif est de renuméroter : 10.8.0.0/24 est une plage RFC1918 archi-courante, et tout VPN tiers (employeur, client, fournisseur) a une chance non négligeable de l’utiliser aussi. Un mesh perso a tout intérêt à se planquer dans un coin moins fréquenté — 10.97.x.0/24, 172.30.x.0/24 — pour ne jamais entrer en collision avec un full-tunnel imposé.

Lessons learned

#sysadmin #networking #wireguard #vpn #routing #lessonslearned

Questions fréquentes

Mon ping répond mais les ports du serveur WireGuard sont filtrés, pourquoi ?
Parce que le ping et le service ne pointent pas forcément vers la même machine. Si un second VPN utilise le même sous-réseau, l’IP que tu pingues peut être la gateway de cet autre VPN, qui répond au ping mais n’héberge aucun de tes services. Lance ip route get 10.8.0.1 : si l’interface n’est pas ton wg0 mais un tun0, c’est un problème de routage, pas de pare-feu.
Deux VPN sur le même réseau 10.8.0.0/24, lequel gagne la route ?
Celui dont la route est la plus spécifique, ou le full-tunnel arrivé en dernier. Un OpenVPN en full-tunnel pose un default via 10.8.0.1 dev tun0 qui détourne tout le trafic du /24, éclipsant silencieusement ton mesh WireGuard. Aucune erreur ni log : ta route par défaut bascule simplement vers le mauvais réseau.
Comment éviter qu’un VPN pro casse l’accès à mon mesh WireGuard perso ?
Renumérote ton mesh sur une plage RFC1918 exotique. Les sous-réseaux 10.8.0.0/24 et 192.168.1.0/24 sont des aimants à collision avec les VPN imposés par un employeur ou un client. Planque ton mesh dans un coin moins fréquenté comme 10.97.x.0/24 ou 172.30.x.0/24 pour ne jamais entrer en collision avec un full-tunnel.
Quel est le premier réflexe de debug quand un service réseau était joignable il y a cinq minutes ?
Commence par ip route get <ip> et non par ping <ip> : la route te dit par quelle interface et vers quelle machine tu sors réellement. Et « ça marchait il y a cinq minutes » signifie que l’environnement a changé, pas le service ; cherche le changement de contexte (ici l’activation d’un autre VPN) avant de soupçonner la cible.

Partager cet article :

Article précédent
Répliquer une prod Coolify sans Coolify avec Traefik
Article suivant
Console série muette : c’était la RAM, pas l’UART