Un routeur OpenWrt qui monte un full-tunnel WireGuard vers mon VPS, pour faire sortir tout un LAN par l’IP du serveur. Sur le papier, propre. À l’usage : « la connexion rame ». Sauf que le diagnostic est contre-intuitif.
Le symptôme qui trompe
Depuis un poste derrière le tunnel :
$ ping -c5 1.1.1.1
5 packets transmitted, 5 received, 0% packet loss
rtt min/avg/max = 12.2/17.5/27.1 ms ← parfait
$ curl -o /dev/null https://speed.cloudflare.com/__down?bytes=100000000
débit : 584 B/s ← mort
Le ping est nickel, le débit s’effondre à quelques centaines d’octets par seconde. En coupant le VPN : 21 Mo/s, instantané. On accuse spontanément la bande passante, le routeur, le disque… tout sauf le vrai coupable.
Ce que ça veut dire
Petits paquets → OK. Gros transferts → morts. C’est exactement la signature d’un trou noir MTU/MSS.
WireGuard ajoute ~60 octets d’en-tête au paquet encapsulé. Le tunnel a donc un MTU effectif d’environ 1420 octets. Or les clients du LAN, eux, croient être sur du 1500 : ils annoncent un MSS de 1460. Le serveur distant leur renvoie donc des paquets de 1500 octets… qui ne rentrent pas dans le tunnel de 1420. Avec le bit Don’t Fragment et un PMTUD cassé, ces paquets sont jetés en silence. La connexion TCP s’établit (petits paquets), puis se fige dès qu’il faut transférer des données.
Le diagnostic côté serveur
$ ip link show wg0 | grep -o 'mtu [0-9]*'
mtu 1420 ← bon
$ sudo iptables -t mangle -S | grep -i mss
← RIEN. C'est ça le problème.
Le MTU du tunnel est correct, mais aucun MSS clamping n’est configuré. Le noyau ne rabote donc jamais le MSS, et les grosses trames se perdent.
Le correctif : MSS clamping
Le MSS clamping intercepte les SYN TCP et abaisse le MSS annoncé à la taille du tunnel (~1380). Les deux bouts négocient alors d’emblée des segments qui rentrent.
Sur OpenWrt (le bon endroit — il possède les clients du LAN) :
- LuCI : Network → Firewall → la zone qui contient l’interface WireGuard → cocher « MSS clamping ».
- En uci :
uci set firewall.@zone[N].mtu_fix='1' && uci commit firewall && /etc/init.d/firewall restart.
En iptables (filet côté serveur, couvre tous les clients du tunnel) :
$ sudo iptables -t mangle -A FORWARD -o wg0 \
-p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
Et on vérifie que l’interface WireGuard est bien à MTU 1420 des deux côtés.
Lessons learned
- Ping OK + gros transferts morts = trou noir MTU. Ce n’est jamais la bande passante ; c’est la taille des paquets.
wg-quickpose MTU 1420 tout seul, mais un tunnel monté à la main ou un routeur qui NAT son LAN dans le tunnel oublie souvent le MSS clamping — obligatoire dès qu’on route un LAN entier.- Testez toujours un vrai transfert, pas juste un ping. Un
curlde quelques Mo révèle en 2 secondes ce qu’un ping ne verra jamais. - Le MSS clamping se pose là où vivent les clients (le routeur du LAN), avec un filet de sécurité sur la passerelle de sortie.