====== Sombres Histoires de MTU ======
===== Trop long, je me fout des détails =====
Sur le réseau Baionet, derrière le VPN,
utilisez une MTU de 1416 en IPv4-only, une MTU de 1396 en IPv6 ou dual stack.
===== Vous avez dit MTU? =====
Vu de haut, c'est très simple: la MTU est la taille maximale que peut
atteindre un paquet. Si un paquet dépasse cette taille maximale, il
sera rejeté par le routeur au lieu d'être transféré.
De base, pour Ethernet v2, la MTU d'un paquet sera de 1500 octets, c'est
plus ou moins standard. Jusque ici, tout va bien. Les problèmes
commencent à apparaître lorsque, comme dans le cas d'un VPN, on
tunnelle une connexion.
Tout d'un coup, on va s'amuser à mettre un
paquet entier dans le corps d'un autre paquet. Dès lors, on comprend
que si l'on s'amuse à mettre un paquet de 1500 octets dans un autre
paquet, le tout dépassera la taille de 1500 octets à cause des headers
du paquet + headers divers (wireguard, etc.).
{{:travel-wifi-vpn-packet.png?400|}}
C'est pourquoi, la plupart du temps, on va mettre une MTU inférieure à
1500 sur l'interface qui va se charger de tunneler les paquets. L'interface wireguard dans notre cas
===== Comment calculer la MTU? =====
Pour cette section, on va prendre le cas du VPN Baionet pour exemple.
Nous avons un premier tunnel GRE qui relie le serveur VPN a son
transit, suivi d'un second tunnel wireguard qui relie le VPN au
client.
La MTU du client sera donc de:
1500 - headers IP (GRE) - Headers GRE - headers IP (wireguard) - headers wireguard
Les headers wireguard prendront toujours 40 octets. Cf. https://lists.zx2c4.com/pipermail/wireguard/2017-December/002201.html
Les headers GRE 4 octets.
Si vous ne faites que de l'IPv4, on peut partir du principe que les
headers IP prennent 20 octets, on aura une MTU de:
1500 - 20 - 4 - 20 - 40 = 1416
Pour un dual stack IPv6, on va prendre la taille des headers v6: 40
octets, on aura une MTU de:
1500 - 20 - 4 - 40 - 40 = 1396
Il va donc falloir utiliser une MTU de 1396 sur votre interface
wireguard.
===== Plot Twist du Routeur =====
Vous mettez le tunnel en place sur votre ordinateur, tout va bien.
Puis, vous montez le même tunnel sur un routeur, vous redirigez tout le
monde dessus, et là, tout à coup, rien ne va plus ! La connexion
est très lente, certains sites ne chargent pas.
W-T-F?
Votre routeur connaît bien la MTU et fait bien attention à la taille maximale des paquets, mais ce
n'est pas le cas des clients! Eux, ne savent même pas qu'ils
passent par un tunnel wireguard.
Comment communiquer la MTU aux clients du coup?
Il y a trois façons de faire ça.
==== Via la découverte PMTU ====
https://fr.wikipedia.org/wiki/Path_MTU_discovery
L'idée ici, c'est que le client va envoyer des paquets de test de
taille décroissante jusqu'à ce que ça passe. Il va ensuite sauver la
taille maximale pour laquelle "ça passe" et va ré-utiliser ça comme
MTU.
C'est la solution la plus propre et efficace, mais elle a le malheur
de se baser sur le protocole ICMP, qui est souvent bloqué par des
firewalls peu scrupuleux pour des raisons de sécurité.
Ce qu'il faut malheureusement retenir de cette solution, c'est que ça
ne marche pas.
==== Via DHCP/RA ====
Le routeur peut envoyer une MTU à utiliser sur le lien lors de la
négociation de l'adresse IPv4 en DHCP et de l'adresse IPv6 en Router
Advertisement. Vous allez donc configurer votre daemon DHCP/RA pour
partager une MTU de 1396 octets.
Ça marche très bien sur la majorité des clients linux/mac/android, en
revanche, ça ne marche pas avec les machines windows.
Ça peut être la solution parfaite pour vous si vous n'avez pas de
windows derrière le routeur.
==== Le dirty hack ====
J’imagine que vous le voyez venir: les solutions propres existantes
ne marchent pas dans la pratique, les ingés télécom ont donc trouvé
une solution qui marche a peu près partout mais qui est bien
dégueulasse: ré-écrire les paquets SYN TCP.
L'idée est de parasiter le handshake TCP pour y ré-écrire un Max
Segment Size (MSS) bidon.
* **Q:** C'est quoi le MSS?
* **R:** C'est la taille de données maximale que peut supporter un paquet TCP. En gros c'est MTU - taille header TCP. En pratique, MTU - 20.
Dans le cas de Baionet, il faudra donc MSS clamper à 1376.
On va donc intercepter tous les messages TCP Syn (demande de
connexion) et ré-écrire le MSS avec la valeur 1376.
Dans la pratique, ça va se faire avec votre firewall.
__sytaxe iptables:__
iptables -t mangle -A POSTROUTING -p tcp --tcp-flags SYN,RST SYN -o wg0 -j TCPMSS --set-mss 1376
__syntaxe nftables:__
Dans votre chaîne forward:
oinfname wg0 tcp flags syn tcp option maxseg size set 1376
* **Q:** on fait quoi pour UDP du coup?
* **R:** aucune idée. Je n'ai pas eu de problèmes avec UDP jusque là...
Une fois cette opération faite sur votre routeur, vous devriez être bon.