Contournement des blocages gouvernementaux de VPN wireguard
Date
12.04.2025
Résumé
Comment avec un ami résidant à l'étranger nous avons déjoué les blocages gouvernementaux du VPN wireguard que nous utilisons pour administrer de manière sécurisée une infrastructure partagée.
Billet
Il se trouve qu'il réside dans une pays, qu'on ne citera pas non plus, qui de notoriété publique est en train de fermer de plus en plus de portes au frontières de son réseau internet. Après avoir vérifié nos configurations dans tous les sens et testé qu'avec les même paramètres ça fonctionnait bien pour des machines localisées en France mais que ça ne passait pas pour des machines localisées chez lui, l'hypothèse d'un blocage gouvernemental est vite devenue l'explication la plus probable.
Et une recherche rapide nous a confirmé qu'il était relativement simple pour des DPI (Deep Packet Inspection) de détecter du traffic wireguard et de le bloquer. En effet le protocole wireguard à été conçu avant tout pour maximiser les performances et chiffrer les données transmises, mais pas pour masquer le fait que les données transmises passent par un VPN. Il y a dans le protocole des échanges de paquets qui ont toujours la même taille et dont les premiers octets sont toujours les mêmes.
Puis nous avons ajouté sa configuration dans
La partie qui créé le fichier de configuration dans
Le contenu du fichier xray-config.json est le suivant :
Le problème
Avec un ami qu'on ne citera pas (sauf s'il veut se "dénoncer" ;-) , nous avons passé plusieurs jours à se demander pourquoi depuis quelques temps il n'arrivait plus à établir de connexion à son VPN openvpn de chez ARN, qu'il utilise pour exposer sur internet son petit serveur YunoHost lui servant à auto-héberger ses services numériques, et plus récemment au VPN wireguard que nous utilisons pour travailler ensemble de manière sécurisée sur des serveurs. Au début nous pensions que ses problèmes avec openVPN venaient soit d'un mauvaise mise à jour de YunoHost soit d'aléas techniques liés à son fournisseur d'accès à internet. Mais le comportement étrange s’est récemment manifesté avec le VPN wireguard nous a mis la puce à l'oreille : La connections commence par s'établir correctement. Ensuite si on essaye rapidement de faire un ping on arrive à faire passer quelques paquets. Mais au bout de quelques secondes, plus rien ne passe.Il se trouve qu'il réside dans une pays, qu'on ne citera pas non plus, qui de notoriété publique est en train de fermer de plus en plus de portes au frontières de son réseau internet. Après avoir vérifié nos configurations dans tous les sens et testé qu'avec les même paramètres ça fonctionnait bien pour des machines localisées en France mais que ça ne passait pas pour des machines localisées chez lui, l'hypothèse d'un blocage gouvernemental est vite devenue l'explication la plus probable.
Et une recherche rapide nous a confirmé qu'il était relativement simple pour des DPI (Deep Packet Inspection) de détecter du traffic wireguard et de le bloquer. En effet le protocole wireguard à été conçu avant tout pour maximiser les performances et chiffrer les données transmises, mais pas pour masquer le fait que les données transmises passent par un VPN. Il y a dans le protocole des échanges de paquets qui ont toujours la même taille et dont les premiers octets sont toujours les mêmes.
La recherche d'une solution
Nous avons donc commencé à chercher des moyens de contourner ce type de blocage. Plusieurs pistes on été trouvées :- 1. utiliser shadowsocks pour encapsuler le traffic wireguard [1], [2]
- 2. utiliser xray avec les protocoles dokodemo-door et reality pour encapsuler le traffic wireguard [3], [6], [7]
- 3. utiliser un fork de wireguard, comme amnesia par exemple [5], qui rajoute des fonctions de camouflage directement dans le protocole wireguard.
La mise en place de la solution retenue
Notes :- Je ne détaille pas ici l'installation ni la configuration de wireguard, qui est tout a fait classique, sauf pour les spécificités liées à l'encapsulation avec xray
- Dans les exemples de configuration il faut remplacer les variables du genre $USER_ID, $PRIVATE_KEY, $SHORT_ID, ..., par les valeurs générées à l'aide des commandes suivantes (à exécuter après l'installation de xray)
# Generate X25519 keys using Xray's built-in command _x25519=$(xray x25519) PRIVATE_KEY=$(echo "$_x25519" | awk -F': ' '/Private key/{print $2}') PUBLIC_KEY=$(echo "$_x25519" | awk -F': ' '/Public key/{print $2}') # Generate a unique UUID for the client CLIENT_UUID=$(uuidgen) # Generate a random short ID SHORT_IDS=$(openssl rand -hex 8) # Define server address and port SERVER_ADDRESS="IP address or DNS name of your wireguard server" PUBLIC_PORT=8443 PRIVATE_PORT=6666- Le port public choisi pour xray est le 8443. L'idée étant de faire croire qu'il s'agit d'une connexion https normale, le mieux serait d'utiliser le port 443. Mais comme nous avons un serveur web sur la même IP, on a pris le port 8443 pour éviter tout conflit. Il devrait être possible de tout mettre sur le port 443 en utilisant un reverse proxy SNI. Nous testerons ça plus tard.
- Le port privé est le port sur lequel écoute le serveur wireguard. Il n'a pas besoin d'être ouvert au niveau du firewall si les seuls clients qui s'y connectent passent par xray. Quand on passe par xray, on s'y connecte uniquement via l'interface loopback.
- Dans les exemples de configuration, on peut voir du google. C'est le nom du serveur web qui est utilisé pour camoufler le traffic. Il n'y à aucune connexion effective vers ce serveur. Et google c'est juste à titre d'exemple parce-que nous ne voulons pas dévoiler le nom que nous avons réellement utilisé. Il convient de choisir un nom DNS qui ne soit pas bloqué des deux coté du VPN et qui n'attire pas l'attention. Il y à d'autres contraintes a respecter [13]
installation de xray sur le serveur
Coté serveur, wireguard tourne sur une machine sous Debian. Nous avons donc installé la version beta de xray comme indiqué dans les tutos que nous avons trouvé avecbash -c "$(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh)" @ install --beta -u rootPuis nous avons ajouté sa configuration dans
/usr/local/etc/xray/config.json :
{
"log": {
"loglevel": "debug"
},
"inbounds": [
{
"listen": "0.0.0.0",
"port": $PUBLIC_PORT,
"protocol": "vless",
"settings": {
"clients": [
{
"id": "$USER_ID",
"flow": ""
}
],
"decryption": "none"
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"show": false,
"dest": "www.google.com:443",
"xver": 0,
"serverNames": [
"www.google.com"
],
"privateKey": "$PRIVATE_KEY",
"shortIds": [
"$SHORT_ID"
]
}
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct"
}
]
}
Modification de la configuration wireguard du serveur
Ensuite nous avons modifié la configuration du serveur wireguard, dans sa section[Interface], pour qu'il écoute sur le port privé ( ListenPort = $PRIVATE_PORT) et pour limiter le MTU à 1300 octets (MTU = 1300). La modification du MTU est nécessaire pour tenir compte de l'overhead ajouté par l'encapsulation xray. Sans cela la taille des paquets réseau pourrait grossir au delà du MTU standard, ce qui causerait des soucis.
Intallation de xray sur le client
Le client est une machine qui tourne sous NixOS. Pour installer une version de xray compatible avec la version installée sur le serveur nous avons du passer la machine en version instable de nixpkgs (on aurait pu être plus subtil et n'installer que xray depuis nixpkgs instable, mais on voulait aller vite pour valider la solution) Comme xray est packagé pour NixOS, il suffit d'ajouter ça dans le configuration.nix de la machine pour l'installer :
services.xray = {
enable = true;
settingsFile = "/etc/xray/config.json";
};
environment.etc."xray/config.json" = {
source = /var/src/secrets/xray-config.json;
user = "root";
group = "root";
mode = "0444";
};
La partie qui créé le fichier de configuration dans
/etc/xray/config.json à partir de /var/src/secrets/xray-config.json est spécifique à la manière de déployer NixOS que nous utilisons pour cette machine (krops + passwordstore). Et les permissions que nous avons mises sur le fichier sont un peu large (toujours en mode quick and dirty pour ces premiers tests). Il y a d'autres manière de définir la configuration de xray sous NixOS, voir sur https://search.nixos.org/options?channel=24.11&from=0&size=50&sort=relevance&type=packages&query=xrayLe contenu du fichier xray-config.json est le suivant :
{
"log": {
"loglevel": "warning"
},
"inbounds": [
{
"tag": "wireguard",
"port": $PRIVATE_PORT,
"protocol": "dokodemo-door",
"settings": {
"address": "127.0.0.1",
"port": $PRIVATE_PORT,
"network": "udp"
}
}
],
"outbounds": [
{
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "$SERVER_ADDRESS",
"port": $PUBLIC_PORT,
"users": [
{
"id": "$USER_ID",
"encryption": "none",
"flow": ""
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"show": false,
"fingerprint": "chrome",
"serverName": "www.google.com",
"publicKey": "$PUBLIC_KEY",
"shortId": "$SHORT_ID",
"spiderX": ""
}
},
"tag": "proxy"
}
]
}
Modification de la configuration wireguard sur le client
Et enfin il fallait modifier la configuration wireguard sur le client :- d'une part dans sa section
[Interface]pour limiter le MTU à 1300 octets (MTU = 1300), comme pour le serveur - d'autre part dans la section [Peer] correspondante au serveur wireguard, pour utiliser comme adresse de destination celle du service xray local au lieu de la véritable adresse du serveur wireguard (
Endpoint = 127.0.0.1:$PRIVATE_PORT) - et enfin, pour que la machine cliente puisse rediriger tout son trafic internet via le VPN wireguard, il fallait changer le paramètre
allowedIPsde la section [Peer] correspondante au serveur wireguard. En effet, si on laisse0.0.0.0/0, ::/0, on redirige aussi le trafic destiné a xray à l’intérieur du VPN. Et du coup ça se mord la queue et ne fonctionne plus. Pour ce faire on peut s'aider du site https://www.procustodibus.com/blog/2021/03/wireguard-allowedips-calculator qui permet de générer une liste de plages IP qui englobe tout internet sauf certaines adresses.
Résultats
Après un peu de débug de configuration réseau (configurations firewall et forward de port entre l'hyperviseur et la VM qui héberge le serveur wireguard qui sous le coup de la fatigue nous avions un peu foirées) la solution s'est avérée efficace. Il était de nouveau possible pour mon ami de se connecter à un VPN wireguard en dehors de son pays. Il à ensuite pu également se connecter à son VPN openvpn, en passant par ce VPN wiregard (évidemment faire passer openvpn à l’intérieur de wireguard qui lui même passe à l’intérieur de xray n'est pas optimal. Mais ça valide déjà la possibilité de contourner les blocages actuel mis en place par son pays).Références
- 1. https://lowendtalk.com/discussion/170940/how-to-obfuscate-wireguard-traffic
- 2. https://www.reddit.com/r/WireGuard/comments/ucz53b/hiding_wireguard_with_ssh_to_avoid_restrictions/
- 3. https://btwiusearch.net/posts/wg-xray/
- 4. https://www.protectstar.com/en/blog/blocking-campaign-russia
- 5. https://docs.amnezia.org/documentation/amnezia-wg/*
- 6. https://www.40huo.cn/blog/wireguard-over-vless.html
- 7. https://computerscot.github.io/wireguard-over-xray.html
- 8. https://cscot.pages.dev/2023/04/13/cloudflare-warp/
- 10. https://github.com/XTLS/Xray-core
- 11. https://github.com/XTLS/Xray-core/discussions/2954
- 12. https://xtls.github.io/en/config/outbounds/wireguard.html
- 13. https://cscot.pages.dev/2023/03/02/Xray-REALITY-tutorial/#Determine-camouflage-website