WireGuard imbriqué : le saut intermédiaire ne peut pas répondre à son propre port
Quand le saut intermédiaire envoie tout dans un seul tunnel, les réponses à son service entrant sortent par le mauvais chemin. Une règle de port source sur l’interface corrige cela.
Trois sauts WireGuard atteignent un réseau sans adresse publique, puis la machine intermédiaire cesse de répondre sur le port où elle était censée écouter. Le tunnel en aval fonctionne toujours, l’hôte distant répond toujours, et seul le serveur intermédiaire lui-même est devenu silencieux de l’extérieur. Cette combinaison est déroutante précisément parce qu’elle est auto-infligée : le saut intermédiaire obéit à sa propre table de routage, et la table envoie ses réponses dans la mauvaise direction.
Une chaîne qui fonctionne jusqu’à ce qu’on parle à la boîte du milieu
Prenons une chaîne illustrative : le client A atteint le serveur B sur UDP 500, et B atteint plus loin le serveur C sur UDP 500. C n’accepte le trafic que de l’adresse de son unique pair, ce qui en fait une feuille et garde son comportement simple. B n’est pas une feuille, et tout ce qui est intéressant dans cette panne se passe là.
La distinction compte parce que les rôles de feuille et d’intermédiaire tirent dans des directions opposées. Une feuille peut tout envoyer dans un seul tunnel sans conséquence, puisque rien d’autre n’en dépend. Un saut intermédiaire est à la fois un point de terminaison pour les clients et un client vers le côté distant, et ces deux tâches veulent un routage différent.
Pourquoi la réponse sort par le tunnel
Sur B, l’interface tournée vers C porte AllowedIPs = 0.0.0.0/0 avec la route par défaut correspondante. Chaque paquet que B émet entre donc dans ce tunnel, sauf si quelque chose de plus spécifique prend le dessus.
Un paquet de A adressé à B arrive et est accepté, car B est la destination et la livraison locale se produit en premier. La réponse est un paquet tout neuf généré localement et destiné à l’adresse publique de A, et cette destination correspond à la route par défaut vers le tunnel. C le reçoit, ne possède pas cette adresse et le rejette.
Le symptôme se lit comme un problème de pare-feu ou une inadéquation de clé, et ni l’un ni l’autre n’est vrai ici. Une capture sur le tunnel vers C montre les réponses partir dans la mauvaise direction. Cette seule observation fait gagner plus de temps que n’importe quelle lecture de configuration, alors notez-la avant de commencer à changer les clés. Quiconque n’a pas vu la capture supposera que le tunnel lui-même est cassé.
La réparation étroite : des règles de politique qui correspondent à un port source
Les réponses de la socket d’écoute de B sortent avec le port source 500. Une règle de politique peut y correspondre et renvoyer ces paquets vers la table ordinaire :
ip rule add sport 500 table main priority 100
ip rule add sport 8080 table main priority 101
Les règles de politique sont consultées par ordre de priorité, et la table principale se trouve à 32766, donc une règle à 100 est interrogée avant que la route par défaut du tunnel ait son mot à dire. Ajoutez une entrée par port qui doit rester joignable de l’extérieur et rien de plus, afin que le trafic transféré continue d’utiliser le tunnel pour lequel il a été construit.
Connaissez la limite de cette astuce. Le sélecteur sport correspond aux paquets générés localement, ce qui couvre exactement le cas de la réponse et ne couvre délibérément pas le trafic que B ne fait que transférer pour quelqu’un d’autre. Un service hébergé derrière B a toujours besoin de sa propre réponse, et prétendre le contraire produit un correctif qui fonctionne pour le premier service et échoue pour le second.
Donnez un propriétaire à la règle
Une règle tapée dans une invite disparaît la prochaine fois que l’interface est reconstruite. Dans une installation WireGuard, placez-la là où l’interface est créée et supprimée :
PostUp = ip rule add sport 500 table main priority 100
PostDown = ip rule del sport 500 table main priority 100
Si NetworkManager, un crochet de distribution ou un point d’entrée de conteneur possède l’interface, la paire appartient à ce propriétaire plutôt qu’à un fichier édité à la main. Vérifiez les règles effectives après une reconnexion, pas seulement après le premier démarrage, car le premier démarrage est le cas qui fonctionne toujours.
Comparez les alternatives honnêtement
La règle de port source est l’une des quatre issues, et c’est la plus étroite d’entre elles. Elle a l’avantage de ne pas toucher du tout à la politique du tunnel, ce qui explique pourquoi elle survit généralement aux changements ultérieurs. Les correctifs étroits échouent aussi bruyamment quand ils cessent de s’appliquer, tandis qu’une exception large continue de fonctionner discrètement longtemps après la disparition de sa raison d’être. Cette différence compte plus que l’élégance quand quelqu’un d’autre possède la boîte dans deux ans.
| Approach | What it costs | Where it breaks |
|---|---|---|
| Source-port policy rule | One rule per exposed port | Anything B forwards rather than originates |
| Destination exception route | A route pinned to specific client addresses | Clients whose address changes |
| Stop full-tunnelling on B | Loses the catch-all path toward C | Designs that depend on it |
| Split into two tunnels | More interfaces and more policy | Nothing, at the cost of complexity |
Vérifiez des deux côtés une fois votre choix fait. Depuis A, lancez une connexion vers le port de B et gardez-la occupée un moment. Sur B, faites justifier au noyau le chemin de réponse avec quelque chose comme ip route get <address-of-A> sport 500, et confirmez qu’il nomme l’interface WAN plutôt que le tunnel. Ensuite, vérifiez que quelque chose derrière C répond encore à travers la chaîne, ce qui prouve que l’exception est restée étroite au lieu de devenir un contournement. Enfin, consignez les ports dans les notes de conception, sinon l’opérateur suivant redécouvrira cela sur un autre service.