Étiquette : cyberghost

22 juillet 2026 /

Comment faire passer un seul site (ici x.com) par un VPN, et uniquement lui, pendant que tout le reste de la machine garde sa connexion directe ? C’est ce qu’on appelle un split-tunnel par domaine. Sous Linux, ça se résout élégamment avec un network namespace isolé, un proxy SOCKS et un fichier PAC dans le navigateur. Sous Android, la logique est différente (le VPN y est par application). Voici le guide complet, avec les pièges rencontrés en vrai et une section honnête sur les limites.

Pourquoi ce n’est pas trivial

On pourrait croire qu’il suffit d’activer le VPN et de « router x.com ». En pratique, plusieurs mauvaises pistes se referment vite :

  • VPN sur toute la machine + filtrage par IP : les grands sites sont derrière des CDN aux IP tournantes et partagées. On capterait trop (d’autres sites du même CDN) et pas assez (IP qui changent), et ça toucherait toutes les applications.
  • Network namespace ou VPN par application : ça fait passer toute une application par le VPN, pas un seul domaine.

La bonne approche combine deux idées : sélection par domaine côté navigateur (fichier PAC) et proxy dont la sortie est le VPN, le tout cloisonné pour éviter toute fuite si le tunnel tombe.

Le principe

┌─ Système principal (connexion directe) ───────────────────────┐
│  Firefox ──PAC── si domaine = x.com / twitter / t.co / twimg   │
│                    → proxy SOCKS,  sinon → DIRECT              │
│                         │                                      │
│                         ▼  10.200.200.2:1080 (veth)            │
│  ┌─ netns « vpnx » ─────────────────────────────────────────┐ │
│  │  proxy SOCKS5 ──► tun0 (OpenVPN) ──► x.com (via le VPN)   │ │
│  │  défaut = tun0 ; pas de route de secours = fail-closed    │ │
│  └──────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘

Tout le VPN vit dans un namespace réseau dédié. Le système principal reste en direct ; seul ce qu’on envoie explicitement dans ce namespace (le trafic x.com relayé par le proxy) emprunte le VPN. La résolution DNS se fait dans le namespace, donc à travers le tunnel : pas de fuite DNS. Et si le VPN tombe, il n’y a plus de route de secours : le site échoue au lieu de fuiter (kill-switch par construction).

Prérequis

  • Une distribution type Ubuntu / Debian.
  • Un VPN fournissant une configuration OpenVPN (dans l’exemple : CyberGhost, profil « US », avec ca.crt / client.crt / client.key et un couple identifiant/mot de passe OpenVPN).
  • Les paquets openvpn et microsocks : sudo apt install openvpn microsocks

Partie 1 — Sur le PC (Linux)

Le script

Un seul script gère tout : up (monte le tunnel isolé + proxy + génère le PAC), down (démonte proprement) et status (compare l’IP directe et l’IP via le VPN). Adaptez les chemins OVPN_* et OVPN_HOST à votre fournisseur.

#!/bin/bash
set -uo pipefail
IFS=$'\n\t'

# --- Paramètres (à adapter) ---
NETNS="vpnx"
VETH_HOST="veth-x-h"; VETH_NS="veth-x-n"
HOST_IP="10.200.200.1"; NS_IP="10.200.200.2"; SUBNET="10.200.200.0/24"
SOCKS_PORT="1080"; DNS_NS="1.1.1.1"
OVPN_DIR="$HOME/cyberghost/us"            # dossier contenant openvpn.ovpn + certs
OVPN_CONF="$OVPN_DIR/openvpn.ovpn"
OVPN_HOST="us.exemple-vpn.net"            # nom du serveur (résolu en IP)
AUTH_FILE="$HOME/.config/vpn-x/cg-auth"   # 2 lignes : identifiant / mot de passe
RUN_DIR="/run/vpn-x"; OVPN_PID="$RUN_DIR/openvpn.pid"; SOCKS_PID="$RUN_DIR/microsocks.pid"
PAC_FILE="$HOME/vpn-x-proxy.pac"          # PAC hors dossier caché (cf. piège Firefox Snap)

priv() { sudo "$@"; }

generer_pac() {
  cat > "$PAC_FILE" </dev/null

  # 3. Forward + NAT (porte uniquement le trafic VPN chiffré)
  priv sysctl -q -w net.ipv4.ip_forward=1
  priv iptables -t nat -A POSTROUTING -s "$SUBNET" -o "$wan_if" -j MASQUERADE
  priv iptables -A FORWARD -s "$SUBNET" -o "$wan_if" -j ACCEPT
  priv iptables -A FORWARD -d "$SUBNET" -i "$wan_if" -m state --state RELATED,ESTABLISHED -j ACCEPT

  # 4. OpenVPN dans le namespace (remote épinglé en IP => reconnexion sans DNS)
  priv ip netns exec "$NETNS" openvpn --cd "$OVPN_DIR" --config "$OVPN_CONF" \
      --remote "$server_ip" 443 --auth-user-pass "$AUTH_FILE" --auth-nocache \
      --writepid "$OVPN_PID" --log "$RUN_DIR/openvpn.log" --daemon "openvpn-vpnx"

  # 5. Attente du tunnel
  local i
  for i in $(seq 1 30); do
    priv ip netns exec "$NETNS" ip -4 addr show tun0 2>/dev/null | grep -q "inet " && break
    sleep 1
  done

  # 6. Kill-switch : route serveur épinglée + suppression de la route de secours
  priv ip netns exec "$NETNS" ip route replace "${server_ip}/32" via "$HOST_IP"
  priv ip netns exec "$NETNS" ip route del default via "$HOST_IP" 2>/dev/null || true

  # 7. Proxy SOCKS5 dans le namespace
  priv ip netns exec "$NETNS" microsocks -i "$NS_IP" -p "$SOCKS_PORT" >"$RUN_DIR/microsocks.log" 2>&1 &
  sleep 1; pgrep -x microsocks | head -1 > "$SOCKS_PID"

  generer_pac
  echo "Prêt. PAC : file://$PAC_FILE"
}

action_down() {
  [[ -f "$SOCKS_PID" ]] && { priv kill "$(cat "$SOCKS_PID")" 2>/dev/null || true; priv rm -f "$SOCKS_PID"; }
  [[ -f "$OVPN_PID" ]]  && { priv kill "$(cat "$OVPN_PID")"  2>/dev/null || true; priv rm -f "$OVPN_PID"; }
  local wan_if; wan_if=$(ip route show default | awk '/default/ {print $5; exit}')
  priv iptables -t nat -D POSTROUTING -s "$SUBNET" -o "$wan_if" -j MASQUERADE 2>/dev/null || true
  priv iptables -D FORWARD -s "$SUBNET" -o "$wan_if" -j ACCEPT 2>/dev/null || true
  priv iptables -D FORWARD -d "$SUBNET" -i "$wan_if" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || true
  priv ip netns del "$NETNS" 2>/dev/null || true
  priv ip link del "$VETH_HOST" 2>/dev/null || true
  priv rm -rf "/etc/netns/${NETNS}"
}

action_status() {
  echo -n "IP directe : "; curl -s --max-time 8 https://api.ipify.org; echo
  echo -n "IP via VPN : "; curl -s --max-time 12 --socks5-hostname "${NS_IP}:${SOCKS_PORT}" https://api.ipify.org; echo
}

case "${1:-}" in
  up) action_up ;; down) action_down ;; status) action_status ;;
  *) echo "Usage : $0 {up|down|status}" ;;
esac

Le fichier d’identifiants

Le script lit l’identifiant et le mot de passe OpenVPN depuis un fichier à deux lignes, en chmod 600 — jamais en dur dans le script :

mkdir -p ~/.config/vpn-x
printf '%s\n%s\n' "VOTRE_IDENTIFIANT_OPENVPN" "VOTRE_MOT_DE_PASSE" > ~/.config/vpn-x/cg-auth
chmod 600 ~/.config/vpn-x/cg-auth

Configurer Firefox (fichier PAC)

  1. Paramètres → Vie privée et sécurité → Sécurité logicielle et des connexions → Paramètres de Proxy → Configurer le proxy… (chemin des versions récentes de Firefox ; sur d’anciennes versions : Général → Paramètres réseau).
  2. Cocher « Adresse de configuration automatique du proxy (.pac) » et coller : file:///home/VOTRE_USER/vpn-x-proxy.pac
  3. Dans about:config, passer network.proxy.socks_remote_dns à true (résolution DNS côté proxy = anti-fuite).

⚠️ Piège Firefox Snap (Ubuntu récent). Le Firefox installé en Snap n’a pas accès aux dossiers cachés comme ~/.config/. Un PAC placé là est silencieusement ignoré, et le site part en direct sans erreur visible. Solution : mettre le PAC dans un chemin non caché du dossier personnel (ici ~/vpn-x-proxy.pac), accessible via l’interface Snap home.

Démarrage automatique au boot (systemd)

Pour ne jamais oublier de le lancer, un service systemd le monte après le réseau et le démonte à l’extinction. Il tourne sous votre compte (il élève via sudo) :

[Unit]
Description=Split-tunnel VPN pour x.com
After=network-online.target
Wants=network-online.target

[Service]
Type=oneshot
RemainAfterExit=yes
User=VOTRE_USER
Group=VOTRE_USER
Environment=HOME=/home/VOTRE_USER
ExecStart=/home/VOTRE_USER/scripts/vpn_x_split.sh up
ExecStop=/home/VOTRE_USER/scripts/vpn_x_split.sh down

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now vpn-x.service
systemctl status vpn-x

Le mode oneshot + RemainAfterExit=yes laisse openvpn et microsocks tourner dans le cgroup du service ; systemctl stop tue tout proprement.

Vérifier que ça marche

La commande status doit montrer deux IP différentes (directe vs VPN). Pour confirmer que le navigateur route bien le bon domaine, on observe les connexions dans le namespace pendant qu’on charge le site :

# IP de sortie comparée
./vpn_x_split.sh status

# Connexions actives dans le tunnel (charger x.com dans Firefox d'abord)
sudo ip netns exec vpnx ss -tn state established

# Preuve côté proxy
tail -f /run/vpn-x/microsocks.log   # doit lister x.com / video.twimg.com …

En parallèle, une page « quelle est mon IP » ouverte dans Firefox doit afficher votre IP normale (le reste passe en direct), tandis que le trafic du site ciblé sort par l’IP du VPN.

Partie 2 — Sur Android

Sur Android, impossible de filtrer par domaine : l’API VPN est par application et exclusive (un seul VPN actif à la fois). L’équivalent réaliste, c’est de router une seule application (l’app du service, ou un navigateur dédié) dans le VPN.

Attention : le split-tunneling intégré de nombreux clients VPN (dont CyberGhost) fonctionne uniquement en mode exclusion (choisir les apps qui contournent le VPN). Pour n’envoyer que l’app voulue, il faudrait exclure toutes les autres : impraticable.

La solution : l’application OpenVPN for Android (d’Arne Schwabe — pas « OpenVPN Connect »), qui propose une liste « Allowed Apps » en mode inclusif.

Préparer un profil .ovpn mono-fichier

OpenVPN for Android importe plus facilement un .ovpn avec les certificats intégrés en ligne. On le fabrique à partir des fichiers de la configuration manuelle :

SRC=~/cyberghost/us
OUT=~/vpn-us-android.ovpn
grep -vE '^\s*(ca|cert|key)\s' "$SRC/openvpn.ovpn" > "$OUT"
{ echo "";   cat "$SRC/ca.crt";     echo ""
  echo ""; cat "$SRC/client.crt"; echo ""
  echo "";  cat "$SRC/client.key"; echo ""; } >> "$OUT"
chmod 600 "$OUT"

On n’intègre pas le mot de passe : l’app le demandera et le mémorisera. Transférez le fichier sur le téléphone par un canal privé (câble USB, partage réseau local…) — il contient votre clé privée.

Sur le téléphone

  1. Installer OpenVPN for Android (Play Store / F-Droid).
  2. Importer le .ovpn.
  3. Saisir identifiant / mot de passe OpenVPN (cocher « enregistrer »).
  4. Éditer le profil → onglet « Allowed Apps »désactiver « VPN utilisé pour toutes les applications sauf celles sélectionnées » pour basculer en mode inclusif (« VPN utilisé uniquement pour les applications sélectionnées ») → cocher uniquement l’app voulue.
  5. Se connecter en tapant sur le nom du profil.

Toujours actif : Android → Paramètres → VPN → ⚙️ → « VPN permanent ». Laissez « Bloquer les connexions sans VPN » désactivé : en mode inclusif, seule l’app ciblée passe par le tunnel, donc le lockdown couperait Internet à toutes les autres. Pensez aussi à passer l’app en batterie « sans restriction » pour que le système ne la tue pas.

Les pièges rencontrés (en vrai)

  • AUTH_FAILED avec CyberGhost : les profils .ovpn manuels utilisent des identifiants OpenVPN dédiés, différents du token du client CLI. Récupérez les bons depuis vos connexions VPN existantes (par ex. nmcli -s -g vpn.secrets connection show NOM pour le mot de passe, nmcli -g vpn.data … pour l’identifiant).
  • Firefox Snap + PAC ignoré : dossier caché inaccessible → PAC hors ~/.config (voir plus haut).
  • Redirection de log en échec : sous sudo, la redirection > fichier s’exécute côté utilisateur ; si le dossier appartient à root, elle échoue. On rend le dossier de run inscriptible (chown) avant de lancer les démons.
  • PID du proxy : sous sudo ip netns exec …, capturez le vrai PID avec pgrep -x microsocks plutôt que $! (qui pointe le wrapper).

Limites — à lire avant de se croire invisible

Ce montage fait une chose précise : faire sortir un site par une IP différente. Ce n’est pas de l’anonymat, et il faut être honnête sur ce qu’un VPN ne fait pas :

  • Si vous êtes connecté à un compte, l’IP ne change rien à votre identification par ce compte.
  • Le fingerprinting du navigateur/appareil vous identifie indépendamment de l’IP.
  • Le fournisseur VPN voit votre trafic sortant : vous déplacez la confiance, vous ne la supprimez pas (les promesses « no-log » sont des affirmations, pas des garanties vérifiables).
  • Un VPN ne change ni votre juridiction, ni l’historique déjà enregistré côté service avant sa mise en place.
  • Sur Android, c’est par application : si vous ouvrez le même service dans une autre app hors tunnel, l’IP réelle fuit.

Autrement dit : excellent pour la confidentialité au quotidien et le choix de l’IP de sortie ; insuffisant, à lui seul, pour un vrai objectif d’anonymat (qui relève d’outils et d’une discipline d’usage bien plus larges : Tor, cloisonnement strict des identités, etc.).

Conclusion

Avec un network namespace, un proxy SOCKS et un PAC, on obtient sur Linux un split-tunnel par domaine propre, avec kill-switch et démarrage automatique. Sur Android, on retombe sur du par application via OpenVPN for Android en mode inclusif. Deux approches différentes pour un même besoin — et surtout, une bonne compréhension de ce que ça protège… et de ce que ça ne protège pas.