À un instant le portable est sur le Wi-Fi du bureau, à l’autre il est attaché à un téléphone, et l’indicateur du tunnel est de nouveau vert avant que vous ayez fini de changer de fenêtre. Un voyant vert indique seulement que le tunnel s’est reconnecté ; ce que la politique de routage et de blocage a fait pendant l’interruption est une autre question. Cette politique est un ensemble de conditions de correspondance compilées lors de sa dernière installation, et elle nomme une interface, une adresse et une famille d’adresses que le transfert vient de supprimer. Le même basculement produit donc trois issues qui se ressemblent : le blocage continue, la politique bloque sa propre reprise, ou un chemin s’ouvre que rien ne couvre.

Rien à l’écran ne distingue ces trois états, demandez donc à quels identifiants les règles étaient accrochées plutôt que de quelle couleur est l’indicateur. Sous Linux une règle peut nommer une interface ou un ipset rempli depuis celle-ci ; sous Android on peut dire à un VpnService quels réseaux sous-jacents suivre via setUnderlyingNetworks. Chaque attache pointe vers une liaison sur le point d’être remplacée, et chacune doit être réévaluée ensuite.

Ce que le transfert réécrit réellement

Quand l’ancienne liaison disparaît, le noyau en retire les adresses, retire les routes qui passaient par elle et reconstruit la sélection d’adresse source à partir de ce qui reste. La route par défaut passe à la nouvelle passerelle, et l’index d’interface auquel les anciennes règles se référaient a disparu ou est recyclé pour un autre périphérique. Les résolveurs par liaison sont aussi rafraîchis, mais pas au même instant que les routes. Tout cela se passe sous le client VPN, donc un client qui ne surveille que l’état de son propre tunnel n’en voit rien.

Le problème est qu’une règle encode un identifiant précis au lieu de l’intention derrière. Une règle qui jette tout ce qui ne sort pas par l’interface du tunnel encode un nom d’interface ; une règle qui autorise le point de terminaison encode une adresse que le nouveau réseau peut router ailleurs. Quand l’identifiant disparaît, la règle ne devient pas visiblement fausse : soit elle cesse de correspondre à quoi que ce soit, soit elle correspond à la mauvaise chose.

Reconstruire le tunnel externe sans percer de trou

Le transport externe était lié à l’ancienne adresse source, il doit donc ouvrir une nouvelle socket depuis la nouvelle. Quand le point de terminaison est un nom d’hôte plutôt qu’une adresse littérale, une résolution doit réussir pendant que le blocage est encore en vigueur. C’est le piège de l’ordre : une politique assez stricte pour jeter tout sauf le point de terminaison jettera aussi la résolution nécessaire pour le trouver, à moins que la résolution n’ait lieu avant la levée du blocage ou ne soit portée par un tunnel encore vivant. Les deux ordres peuvent fonctionner, mais seulement si le client sait dans lequel il se trouve.

Les clients diffèrent ici d’une manière qui compte au diagnostic. Certains résolvent d’abord et installent les règles ensuite, si bien qu’un transfert coûte une panne visible puis se rétablit seul ; d’autres maintiennent le blocage et comptent sur le tunnel survivant pour porter la résolution, ce qui échoue complètement quand le tunnel est mort avec la liaison. Ajouter une route directe par défaut large pour rétablir la connectivité fait toujours passer le test et laisse toujours la fuite que vous empêchiez.

Une route qui pointe encore vers l’ancienne passerelle donne la même reprise coincée par une autre cause, alors lisez la table avant d’accuser le client. Les commandes ci-dessous nomment l’interface et l’adresse source que le noyau utiliserait réellement, ce qui tranche en une ligne si l’ancien chemin est toujours installé.

ip route get 1.1.1.1
ip -6 route get 2606:4700:4700::1111

Quand la nouvelle liaison apporte l’IPv6 et pas les règles

Les réseaux mobiles et invités distribuent souvent un préfixe IPv6 global même quand le LAN filaire du bureau ne l’a jamais fait. Une politique écrite uniquement en règles IPv4, la forme par défaut de la plupart des recettes iptables et nftables faites à la main, n’en couvre rien. Le tunnel reste connecté, les applications joignables en IPv6 sortent en dehors, et l’indicateur ne peut pas montrer la différence parce que le tunnel est vraiment levé. Le cas miroir est tout aussi courant : un jeu de règles réservé à l’IPv6 ne fait rien du tout sur un réseau qui n’offre pas de v6.

Comparez ce que la liaison offre avec ce que la politique mentionne, des deux côtés du transfert. Ces commandes impriment les mêmes faits que ceux avec lesquels le client travaille :

ip -4 route show default
ip -6 route show default
sudo nft list ruleset | grep -c 'ip6 '

Si la deuxième commande imprime une route par défaut alors que la troisième renvoie zéro, la nouvelle liaison peut faire sortir la machine en IPv6 sans qu’aucune règle ne la surveille. Relancez les trois après le basculement, car le nombre intéressant est la différence entre les deux exécutions. Si la deuxième n’imprime rien, le cas inverse s’applique et toute politique chargée en v6 n’y est que décoration.

Le résolveur change de mains en pleine session

Sur les systèmes modernes les résolveurs sont attachés aux liaisons, donc une nouvelle liaison arrive avec un nouveau jeu de résolveurs et peut-être une vue split-DNS différente. systemd-resolved tient une portée par liaison et choisit entre elles selon la route, tandis que macOS lit des résolveurs à portée dans le magasin dynamique et respecte l’ordre des interfaces. Un client qui installe son propre résolveur concurrence celui de la liaison, et des règles de priorité que personne ne surveille décident du gagnant. La résolution de noms peut alors casser alors que le filtrage de paquets fait exactement ce pour quoi il a été écrit.

Lisez le résolveur qui est actif plutôt que celui qui est configuré. Sur un hôte systemd la sous-commande status montre de quelle liaison vient chaque portée et si un nom private-DNS est en vigueur :

resolvectl status --no-pager
resolvectl query intranet.example.com

Si la requête sort par la liaison physique plutôt que par le tunnel, le client a perdu la compétition de priorité et aucun réglage de pare-feu ne réparera le nommage. Comparez le chemin de la requête des deux côtés du transfert pour voir lequel a bougé. Un nom qui résout vers une adresse privée que le nouveau réseau ne peut pas router est un troisième cas, et il se présente comme un délai d’attente plutôt que comme une erreur.

Entraînez le transfert et gardez la trace

Reproduisez le changement exprès au lieu de l’attendre. Montez le tunnel sur la première liaison, lancez un transfert long et une résolution répétée, puis changez de liaison et regardez lequel survit. Notez l’intervalle entre la disparition de l’ancienne liaison et le moment où le tunnel signale qu’il est connecté, car c’est dans cette fenêtre que la politique a tenu ou non. Faites la séquence dans l’autre sens aussi, pour que le résultat ne soit pas à sens unique.

Les exceptions méritent leur propre passe, car un contournement justifié sur l’ancien réseau ne l’est pas automatiquement sur le nouveau. Une imprimante, un NAS ou un portail captif sur le LAN domestique n’a pas d’équivalent en mobile, et l’exception qui l’atteignait devient une règle sans équivalent.

Notez les noms d’interface, les familles offertes, le résolveur en vigueur et la durée de la panne pour chaque direction. Une reconnexion prouve que le transport s’est rétabli, pas que le blocage a tenu pendant l’interruption, et ce sont des affirmations distinctes à mettre dans un ticket. Avec cette trace, le transfert suivant se compare à un état connu plutôt qu’à la mémoire.

Articles similaires