Vous imaginez le serveur VPN lisant l’adresse de votre ordinateur portable dans le paquet et l’inscrivant dans un journal. Ce qu’il lit, c’est ce que le dernier saut NAT a placé dans l’en-tête externe, et sur un téléphone utilisé en partage de connexion il s’agit souvent d’une adresse partagée avec des centaines d’autres abonnés. L’adresse propre de votre machine 192.168.x.x ne traverse jamais internet dans cet en-tête, et l’adresse du tunnel est attribuée par le serveur une fois la connexion déjà établie. Ainsi, quand le journal du serveur et ip addr sur l’ordinateur portable ne concordent pas, ni l’un ni l’autre n’est faux ; ils décrivent des couches différentes d’une même session.

Trois adresses, et une seule figure dans le journal

La confusion vient de la fusion de trois adresses en une. Chacune a un propriétaire différent, vit dans un en-tête différent et atteint le serveur par un chemin différent.

AddressWho assigns itWhere it sitsVisible to the VPN server
Device address, e.g. 192.168.1.24Your router via DHCPOuter header, before translationNo, rewritten in place
Translated address and portRouter, ISP CGNAT, or bothOuter header, after translationYes, this is the tuple it logs
Tunnel address, e.g. 10.8.0.6The VPN server itselfInner header, after decapsulationYes, but it chose it

Seule la ligne du milieu est inconnue au moment de la connexion. Le serveur l’écrit dans sa table de pairs, son fichier d’état ou son journal de flux selon le démon : WireGuard l’appelle le point de terminaison, un fichier d’état OpenVPN l’étiquette Real Address, et strongSwan le signale comme hôte distant de l’IKE_SA. Cette valeur est rafraîchie dès qu’un paquet arrive d’une autre source, elle change donc sans que personne ne redémarre quoi que ce soit.

La ligne du bas est ce que les gens lisent à tort comme une revendication d’identité. Elle marque un emplacement dans la configuration du serveur, pas une personne, car le serveur l’a choisie dans son propre pool. Deux utilisateurs peuvent recevoir la même adresse de tunnel des jours différents, et l’un peut en détenir deux depuis deux appareils.

Pourquoi le tuple journalisé change alors que le tunnel reste actif

La traduction d’adresses est une table avec un minuteur, pas une liaison permanente. Un routeur domestique conserve son mappage UDP un moment après le dernier paquet, une passerelle d’opérateur recycle les ports selon son propre calendrier, et un téléphone qui passe du Wi-Fi à la LTE revient avec une source entièrement différente. Les valeurs par défaut de conntrack sous Linux sont ici un repère utile : nf_conntrack_udp_timeout vaut 30 secondes et la variante streaming 120, si bien qu’un tunnel silencieux peut perdre son mappage bien avant que l’utilisateur ne le remarque.

Le tunnel survit parce que le protocole authentifie le pair, pas l’adresse. WireGuard est sans état après la poignée de main, donc tout paquet authentifié met à jour le point de terminaison enregistré et un reliage se répare au paquet suivant ; c’est pourquoi persistent-keepalive = 25 existe, pour garder le mappage chaud pendant l’inactivité. Le --float d’OpenVPN fait le même travail et permet à un client authentifié de reprendre depuis une nouvelle adresse et un nouveau port. Sur les versions 2.4 et 2.5 où float est désactivé par défaut, un reliage réinitialise la session et le client se reconnecte.

IPsec y parvient avec davantage de pièces mobiles. IKEv2 détecte la traduction en comparant les hachages source et destination dans les charges de détection NAT, passe à l’encapsulation UDP 4500 et suit les keepalives jusqu’au nouveau tuple. Lorsque les keepalives sont bloqués, la SA reste active sur le papier tandis que le trafic dans une direction s’arrête silencieusement.

Ce que le serveur peut attribuer, et ce qu’il ne peut pas

Le mythe qu’il vaut la peine de tuer est que la traduction vous cache de l’opérateur. Elle change l’étiquette, pas l’observation. Une passerelle derrière le NAT de l’opérateur voit l’espace 100.64.0.0/10 ou une adresse publique partagée par de nombreux abonnés, et peut tout de même rattacher le flux à un sujet de certificat, une clé publique WireGuard, une adresse de tunnel attribuée, des compteurs d’octets et une fenêtre temporelle. Rien de tout cela n’a besoin de votre adresse LAN.

Les limites vont aussi dans l’autre sens. Une adresse partagée dans un journal désigne une passerelle, pas un foyer ; deux sessions depuis la même adresse traduite sur des ports différents sont des appareils différents ; la même adresse deux jours différents peut être deux abonnés sans lien si le port a été recyclé. Un serveur qui n’enregistre que les clés des pairs ne peut rattacher l’une à un client sans la base de données des comptes, et un serveur qui n’enregistre que les adresses ne peut distinguer un ordinateur portable d’un téléphone derrière le même routeur.

Comparez les deux extrémités au lieu de deviner

Pour tirer au clair ce qui s’est passé, capturez la même connexion aux deux extrémités au même moment et comparez le tuple, pas l’adresse. Sur le client, avant toute traduction :

ss -uapn 'dport = :51820'
ip -4 route get 203.0.113.10
wg show wg0 endpoints

Lisez ensuite l’entrée de traduction sur le routeur ou la passerelle CGNAT, et ce qui arrive finalement au serveur :

conntrack -L -p udp --dport 51820
tcpdump -ni eth0 udp port 51820

Trois schémas expliquent la plupart des écarts. Le port source côté serveur diffère du port local tandis que la destination correspond : traduction de ports ordinaire. L’adresse source côté serveur appartient à un bloc ISP qui n’est pas le vôtre : au moins une couche NAT supplémentaire. Les paquets s’arrêtent après une période d’inactivité et reprennent avec un nouveau port : le mappage a expiré, pas une panne de routage. Si les horodatages sont séparés de plus d’une seconde ou deux, vous comparez deux tentatives différentes.

Où la différence casse les choses

Les coupures qui ressemblent à des pannes serveur commencent généralement ici. Une règle d’accès épinglée à votre adresse domestique échoue après un changement de bail chez l’ISP. Une règle fail2ban correspondant à une adresse traduite bannit tous les abonnés derrière cette passerelle d’un coup. Un pair site-to-site à adresse distante fixe cesse de renouveler ses clés après un changement de lien mobile. Le protocole du tunnel allait bien ; l’hypothèse sur le tuple externe non.

La même confusion apparaît côté serveur. Si la boîte VPN elle-même se trouve derrière NAT, il vous faut une redirection de port et un chemin de transfert fonctionnel ; le guide de transfert strongSwan couvre ce cas pour IPsec. Un serveur joignable seulement sur une adresse privée ne voit jamais le tuple traduit que présentent ses clients, et c’est un problème différent de la traduction des clients.

Passez ces quatre vérifications dans l’ordre et arrêtez-vous à la première qui échoue :

  • Capturez aux deux extrémités en même temps ; confirmez que le port source, le port de destination et les horodatages concordent.
  • Lisez la liste des pairs du serveur pour l’adresse qu’il détient actuellement, pas celle que vous attendiez.
  • Vérifiez la table conntrack ou NAT pour l’entrée et sa durée de vie restante.
  • Confirmez que l’adresse de l’interface tunnel sur le client correspond à celle attribuée par le serveur, pas à l’adresse LAN.

Si les deux captures concordent sur le tuple et que le tunnel échoue encore, la traduction n’est pas votre problème ; passez à la poignée de main et à la table de routage à l’intérieur du tunnel.

Articles similaires