Vous ne pouvez pas exempter un programme d’un hôte WireGuard en tunnel complet en modifiant les routes. Les routes choisissent un chemin selon la destination, et ce que vous voulez exempter est un processus, donc le noyau n’a rien à comparer. L’approche praticable consiste à donner à ce processus son propre contexte réseau : un espace de noms avec sa propre interface, ses adresses et sa route par défaut, relié à l’hôte par une paire veth. Je l’ai exécuté sur Ubuntu 24.04 avec wireguard-tools 1.0.20210914, et l’espace de noms n’a jamais été le problème — ce sont la politique de transfert de l’hôte et les règles de marquage du tunnel qui l’étaient.

Choisissez d’abord le type de contexte dont vous avez besoin

Deux formes apparaissent en pratique. Si l’hôte fait tourner un tunnel complet et qu’un programme doit sortir par le chemin du FAI, vous construisez un second espace de noms, vous le reliez à l’hôte et vous laissez l’hôte transférer et traduire le trafic pour lui. Si un espace de noms porte déjà une interface VPN et que vous n’avez besoin que d’une commande lancée à l’intérieur, c’est le cas ordinaire d’ip netns exec et l’essentiel du travail de routage est déjà fait.

Aucune des deux formes ne vous donne une règle limitée à un seul identifiant de processus. Netfilter compare des adresses, des ports, des marques et des interfaces ; il n’existe pas de table de routage par processus. Le marquage peut orienter le trafic, mais la marque doit être appliquée à des paquets que vous avez déjà identifiés, et c’est le même problème un cran plus bas. Un espace de noms sépare toute la pile pour cet arbre de processus, et c’est pourquoi c’est la réponse habituelle.

Si l’exigence est vraiment que rien ne sorte du tunnel, arrêtez plutôt le tunnel. L’espace de noms existe pour le cas mixte : un programme dehors, tout le reste dedans, sur la même machine, au même moment.

Construisez le second contexte et reliez-le à l’hôte

Une disposition illustrative : l’hôte a une interface WireGuard qui porte la route par défaut, et un espace de noms réseau nommé clearnet relié à l’hôte par une paire veth. Les adresses ci-dessous sont des exemples.

ip netns add clearnet
ip link add veth-clear-out type veth peer name veth-clear-in
ip addr add 192.168.100.1/24 dev veth-clear-out
ip link set veth-clear-out up
ip link set veth-clear-in netns clearnet
ip netns exec clearnet ip addr add 192.168.100.2/24 dev veth-clear-in
ip netns exec clearnet ip link set veth-clear-in up
ip netns exec clearnet ip route add default via 192.168.100.1

Cet espace de noms peut maintenant atteindre l’hôte et rien d’autre. L’hôte doit transférer le trafic et réécrire l’adresse source, car 192.168.100.0/24 est privée et le routeur en amont n’a aucune route de retour vers elle :

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o <wan-interface> -j MASQUERADE

Confirmez le côté espace de noms avant d’aller plus loin.ip netns exec clearnet ip route devrait afficher la route veth et la route par défaut via 192.168.100.1, et un ping vers cette adresse devrait répondre. Si le ping vers l’adresse de l’hôte échoue, les adresses ou l’état du lien sont faux et aucune règle de pare-feu n’aidera.

Quand les noms se résolvent mais que rien ne revient, lisez FORWARD

La panne classique ressemble à un bug de routage : l’espace de noms résout un nom, le paquet sort et aucune réponse n’arrive jamais. Sur les hôtes dont la politique FORWARD est DROP — plusieurs distributions et la plupart des images durcies le font — le paquet est abandonné en chemin, et l’erreur affichée par l’application ne dit rien du filtrage.

Lisez la chaîne avant d’ajouter quoi que ce soit :

iptables -S FORWARD
nft list chain inet filter forward

Admettez ensuite le trafic dans les deux sens, avec des compteurs, pour savoir si la règle a un jour correspondu :

iptables -A FORWARD -i veth-clear-out -o <wan-interface> -j ACCEPT
iptables -A FORWARD -i <wan-interface> -o veth-clear-out -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
watch -n1 'iptables -L FORWARD -v -n'

Une règle dont le compteur de paquets est à zéro n’est pas sur le chemin. Soit les noms d’interfaces diffèrent de ce que vous supposiez, soit une règle antérieure de la chaîne a accepté, abandonné ou renvoyé le paquet d’abord. Corrigez l’ordre, pas le texte de la règle.

Le trafic de retour est la moitié que l’on oublie. La règle de retour a besoin du même nom veth plus une correspondance d’état de connexion, ou d’une acceptation d’interface simple si vous gardez la politique ouverte. Ajoutez seulement la règle sortante et le symptôme initial revient, votre nouvelle règle bien en place et apparemment correcte.

Gardez les règles de marquage du tunnel hors du nouveau chemin

Cette étape transforme un espace de noms fonctionnel en espace qui fuit. Les installations WireGuard posent généralement une politique de marque pare-feu avec leurs propres règles de routage et une table dédiée, si bien que les paquets non marqués retombent sur la table principale tandis que les paquets marqués utilisent la table du tunnel. Le trafic transféré depuis l’espace de noms est évalué face au routage par politique à la sortie et, selon la façon dont ces règles ont été écrites, il peut atterrir dans la table du tunnel.

Deux ajouts séparent les chemins. Revenez tôt dans la chaîne mangle pour le sous-réseau de l’espace de noms, et ajoutez une règle fondée sur la source qui place ce sous-réseau dans la table principale :

iptables -t mangle -I PREROUTING -s 192.168.100.0/24 -j RETURN
ip rule add from 192.168.100.0/24 lookup main priority 100

La priorité 100 se classe avant les règles du tunnel sur mon hôte, donc la table ordinaire décide pour cette source. Ne copiez pas le nombre aveuglément : les priorités que wg-quick installe diffèrent entre versions et entre les configurations IPv4 et IPv6, exécutez donc ip rule show et choisissez une priorité qui se place devant les règles du tunnel sur votre machine.

Vérifiez avec une recherche propre à la source plutôt qu’en faisant confiance à la liste des règles :

ip route get 1.1.1.1 from 192.168.100.2
ip netns exec clearnet ip route get 1.1.1.1

Si la première commande signale l’interface WireGuard, la nouvelle règle n’est pas encore devant la politique du tunnel. Si elle signale l’interface WAN alors que la seconde montre toujours la route par défaut veth, l’hôte et l’espace de noms sont en désaccord et vous devriez relire les deux tables de routage.

Lancez le processus qui ouvre la connexion

Lancer la commande tient en une ligne, mais lancez le processus qui crée réellement la socket.ip netns exec clearnet curl -s https://ifconfig.me est le plus petit test honnête : il montre l’adresse que l’espace de noms présente au monde, pas celle que l’hôte utiliserait.

Pour un service, attachez l’espace de noms par chemin afin que le processus y reste toute sa vie :

[Service]
NetworkNamespacePath=/run/netns/clearnet

Les applications graphiques sont là où l’approche en une ligne échoue discrètement. Un navigateur lancé depuis un menu confie souvent la requête à une instance déjà en cours d’exécution hors de l’espace de noms, si bien que la nouvelle fenêtre apparaît et le trafic sort encore par le tunnel. Donnez-lui un profil séparé pour qu’une nouvelle instance soit réellement créée, puis vérifiez le contexte du processus au lieu de deviner :

readlink /proc/$(pgrep -f clearnet-profile | head -1)/ns/net
readlink /run/netns/clearnet

Les deux sorties doivent correspondre. La même vérification fonctionne pour tout programme de longue durée, et elle vaut la peine d’être faite une fois par application plutôt que de supposer que le lanceur a fait ce que vous vouliez.

La résolution de noms demande sa propre décision. Créer un espace de noms ne lui donne pas de configuration de résolveur ; des fichiers par espace de noms sont pris en charge via /etc/netns/<name>/resolv.conf et sans cela vous héritez d’un comportement facile à mal lire. IPv6 demande le même traitement : si l’espace de noms n’a pas de route par défaut v6 alors que l’application préfère v6, les requêtes peuvent se bloquer avant de basculer, ce qui ressemble à un tunnel cassé.

Vérifiez le cadrage, pas seulement l’adresse de sortie

Une adresse publique qui fonctionne prouve la route, pas toute l’exigence. Parcourez le reste dans cet ordre :

  • ip netns exec clearnet ip route get 1.1.1.1 affiche la route par défaut veth, pas l’interface WireGuard.
  • Les compteurs FORWARD des deux règles augmentent pendant qu’une requête s’exécute.
  • Le processus de l’application signale l’inode de l’espace de noms attendu.
  • Après un redémarrage, l’espace de noms existe avant le démarrage du service ; une unité qui s’exécute plus tôt échoue ou, pire, s’exécute hors de l’espace de noms.

Décidez ensuite ce qui doit se passer quand le tunnel tombe. L’espace de noms continue de fonctionner, ce qui est le but de l’exercice et aussi le risque : le programme exempté reste connecté pendant que tout le reste s’arrête. Consignez-le comme un choix de politique et soyez clair sur ce que l’exemption ne couvre pas — l’identité du compte, l’état de navigateur enregistré et votre fournisseur DNS se situent tous hors du périmètre d’un espace de noms réseau, et traiter l’exemption comme un anonymat est l’erreur qui survit à la configuration.

Articles similaires