Le trafic IPv6 doit-il passer par le VPN ou en direct ?
Décidez si ::/0 appartient à l'intérieur du tunnel, selon trois conditions : prise en charge de la sortie, joignabilité de l'extrémité et réseaux purement locaux.
Deux personnes m'ont demandé le mois dernier des résultats opposés : l'une voulait qu'IPv6 soit couvert par le VPN, l'autre voulait que l'imprimante du bureau continue de fonctionner. Une seule route ::/0 ne peut pas fournir les deux à elle seule. Savoir si cette route appartient à l'intérieur du tunnel dépend de trois conditions, et la première l'exclut pour la plupart des sorties commerciales. Si la sortie ne transporte pas IPv6, acheminer la route par défaut dedans cache votre trafic dans un tunnel qui n'a nulle part où l'envoyer.
Trois conditions décident de la réponse
La route par défaut tient en une ligne, ::/0, et elle correspond à toute destination IPv6 sans route plus spécifique (RFC 4291). L'installer est facile. Décider si vous devriez le faire revient à trois conditions.
Première condition : la sortie à laquelle vous vous connectez dispose d'IPv6 fonctionnel et accepte de le transmettre. Deuxième condition : votre client peut conserver un chemin vers l'extrémité du tunnel, qui se trouve généralement dans la plage que vous allez router. Troisième condition : vous pouvez nommer les destinations IPv6 locales qui doivent rester hors du tunnel.
Chaque condition échoue à sa manière, et c'est pourquoi deviner coûte une soirée entière. Une première condition ratée vous donne du silence et une table de routage qui semble correcte. Une deuxième condition ratée tue la poignée de main quelques secondes après son début. Une troisième condition ratée laisse un tunnel fonctionnel et un collègue mécontent près de l'imprimante.
| What you see | Decision |
|---|---|
| Exit answers IPv6 probes, no local IPv6 devices to protect | Route ::/0 into the tunnel |
| Exit answers IPv6 probes, printer or NAS reachable by a global address | Route ::/0, then give those prefixes a route of their own |
| Exit is IPv4-only inside the tunnel | Do not route ::/0; block IPv6 on the client |
Endpoint is reached over IPv6 and sits inside ::/0 | Install a host route for the endpoint first |
La sortie transporte-t-elle vraiment IPv6 ?
Une interface de tunnel avec une adresse IPv6 ne prouve rien sur l'autre côté. De nombreux profils commerciaux sont uniquement IPv4 à l'intérieur : le serveur vous donne une adresse v4 et abandonne tout le reste. Installez par-dessus une route par défaut issue de AllowedIPs et le noyau enverra volontiers IPv6 dans une interface dont le pair ne le voit jamais.
Testez depuis le client pendant que le tunnel est actif. ping -6 -c 3 2001:4860:4860::8888 et ip -6 route get 2001:4860:4860::8888 répondent à des questions différentes : si une réponse revient, et quel périphérique le noyau a choisi. Quand le second nomme votre tunnel et que le premier ne renvoie rien, le problème est la sortie, pas la route.
Si vous gérez vous-même la sortie, le test client peut réussir et le chemin aboutir quand même dans une impasse. Confirmez net.ipv6.conf.all.forwarding=1 sur la passerelle et que son pare-feu accepte les paquets transférés hors du tunnel. Un paquet correctement routé vers une sortie qui refuse de relayer ressemble exactement, côté client, à un bogue de routage.
Le client peut-il conserver son chemin vers l'extrémité ?
C'est le cas qui m'a piégé sur un ordinateur portable doté d'une extrémité WireGuard uniquement IPv6. L'adresse de l'extrémité est une adresse globale ordinaire, elle tombe donc dans ::/0. Routez tout le préfixe dans l'interface et les paquets de poignée de main se poursuivent eux-mêmes dans le tunnel qu'ils tentent encore de construire. Le tunnel ne monte jamais, et rien dans la sortie du client n'explique pourquoi.
wg-quick gère cela sous Linux. Il dérive les routes de AllowedIPs, les installe dans sa propre table et ajoute une règle de politique pour que le trafic vers l'extrémité soit d'abord résolu par la table principale : la règle suppress_prefixlength 0 que vous trouvez dans ip -6 rule. C'est pourquoi wg-quick up réussit là où une ip -6 route add default dev wg0 écrite à la main vous coupe.
Vérifiez les deux états avec ip -6 route get <endpoint-v6>, avant et après avoir monté le tunnel. Si la réponse bascule vers votre périphérique de tunnel, vous avez supprimé le chemin dont le tunnel a besoin. Quand vous écrivez les routes vous-même, ajoutez une route d'hôte vers l'extrémité via la passerelle d'origine, ou connectez-vous à l'extrémité en IPv4 et laissez IPv6 à la charge utile.
Que doit rester hors du tunnel ?
Les routes plus spécifiques l'emportent sur la route par défaut, donc un préfixe sur le lien ou une plage ULA avec sa propre route continue de fonctionner sans effort supplémentaire. C'est la raison silencieuse pour laquelle tant d'installations IPv4 en tunnel complet survivent : les préfixes du LAN sont plus spécifiques que la route par défaut et n'entrent jamais dans le tunnel.
Cela casse quand un appareil local est joignable par une adresse globale, ce qui est normal pour une imprimante à qui le même routeur a donné un préfixe public, un NAS ou un téléviseur. Ces adresses correspondent à ::/0 et à rien d'autre, elles migrent donc dans le tunnel avec tout le reste et disparaissent.
Décidez par destination, pas par protocole. Si deux ou trois hôtes locaux comptent, donnez à leurs préfixes une route par l'interface physique, ou retirez-les de l'ensemble négocié. Si la liste ne cesse de grandir, la réponse honnête est le split tunneling pour IPv6 avec une liste d'exceptions écrite, pas une route par défaut que vous rafistolez sans cesse.
Si la réponse est non, bloquez-le
Laisser IPv6 sans route n'est pas la même chose que le laisser tranquille. Un hôte doté d'une route par défaut IPv6 fonctionnelle continue de l'utiliser pendant que le tunnel transporte IPv4, donc le trafic sort à côté du VPN et chaque service qui préfère IPv6 voit votre adresse réelle. C'est une fuite, pas un tunnel scindé.
Choisissez-en une et notez laquelle vous avez choisie. Routez la route par défaut et acceptez les compromis ci-dessus, ou désactivez IPv6 pendant la durée du tunnel. Omettre le préfixe de AllowedIPs ne suffit pas à lui seul, car le système d'exploitation conserve sa propre route par défaut. Sous Linux, la version brutale est sysctl -w net.ipv6.conf.all.disable_ipv6=1 ; la version plus fine fait tomber IPv6 hors du tunnel avec une règle de pare-feu. Les clients mobiles disposent d'un interrupteur explicite de blocage d'IPv6 qui fait le même travail.
Vérifiez-le comme une fuite
Montez le tunnel et lisez l'état au lieu de faire confiance à l'interrupteur. ip -6 route show default devrait afficher une seule route par défaut, et ip -6 route get pour une destination hors de votre LAN devrait nommer le périphérique de tunnel. Répétez les deux après une déconnexion : une route par défaut qui survit au tunnel est le bogue que vous cherchiez.
Testez ensuite l'autre sens. Depuis un hôte du réseau local, joignez le client à son adresse IPv6 locale. Si cela cesse de fonctionner, la troisième condition n'a jamais été remplie, quoi qu'ait affirmé la table de routage à ce moment-là.
Écrivez le résultat là où la personne suivante le trouvera : quels préfixes restent locaux, pourquoi, et ce que fait le client après une déconnexion. Deux lignes dans un runbook évitent au prochain ingénieur de redécouvrir la boucle de l'extrémité à minuit.