Non potete esentare un programma da un host WireGuard a tunnel completo modificando le rotte. Le rotte scelgono un percorso in base alla destinazione, e ciò che volete esentare è un processo, quindi il kernel non ha nulla con cui confrontarlo. L’approccio praticabile è dare a quel processo il suo contesto di rete: uno spazio dei nomi con la propria interfaccia, i propri indirizzi e la propria rotta predefinita, collegato all’host tramite una coppia veth. L’ho eseguito su Ubuntu 24.04 con wireguard-tools 1.0.20210914, e lo spazio dei nomi non è mai stato il problema — lo sono stati la politica di inoltro dell’host e le regole di marcatura del tunnel.

Prima scegliete il tipo di contesto che vi serve

In pratica compaiono due forme. Se l’host esegue un tunnel completo e un programma deve uscire dal percorso dell’ISP, costruite un secondo spazio dei nomi, lo collegate all’host e lasciate che l’host inoltri e traduca il traffico per lui. Se uno spazio dei nomi porta già un’interfaccia VPN e vi serve solo un comando avviato al suo interno, è il caso normale di ip netns exec e gran parte del lavoro di routing è già fatto.

Nessuna delle due forme vi dà una regola limitata a un solo identificatore di processo. Netfilter confronta indirizzi, porte, marcature e interfacce; non esiste una tabella di routing per processo. La marcatura può indirizzare il traffico, ma il marchio va applicato a pacchetti che avete già identificato, e questo è lo stesso problema un livello più in basso. Uno spazio dei nomi separa l’intero stack per quell’albero di processi, ed è per questo che è la risposta abituale.

Se il requisito è davvero che nulla esca dal tunnel, fermate invece il tunnel. Lo spazio dei nomi esiste per il caso misto: un programma fuori, tutto il resto dentro, sulla stessa macchina, nello stesso momento.

Costruite il secondo contesto e collegatelo all’host

Una disposizione illustrativa: l’host ha un’interfaccia WireGuard che porta la rotta predefinita, e uno spazio dei nomi di rete chiamato clearnet collegato all’host tramite una coppia veth. Gli indirizzi qui sotto sono esempi.

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

Quello spazio dei nomi ora può raggiungere l’host e nient’altro. L’host deve inoltrare il traffico e riscrivere l’indirizzo di origine, perché 192.168.100.0/24 è privato e il router a monte non ha alcuna rotta di ritorno al suo interno:

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

Confermate il lato dello spazio dei nomi prima di proseguire.ip netns exec clearnet ip route dovrebbe mostrare la rotta veth e la rotta predefinita tramite 192.168.100.1, e un ping a quell’indirizzo dovrebbe rispondere. Se il ping all’indirizzo dell’host fallisce, gli indirizzi o lo stato del collegamento sono sbagliati e nessuna regola del firewall aiuterà.

Quando i nomi si risolvono ma non torna nulla, leggete FORWARD

Il guasto classico sembra un bug di routing: lo spazio dei nomi risolve un nome, il pacchetto esce e non arriva mai una risposta. Sugli host con una politica FORWARD di DROP — lo fanno diverse distribuzioni e la maggior parte delle immagini indurite — il pacchetto viene scartato lungo il percorso, e l’errore stampato dall’applicazione non dice nulla sul filtraggio.

Leggete la catena prima di aggiungere qualsiasi cosa:

iptables -S FORWARD
nft list chain inet filter forward

Poi ammettete il traffico in entrambe le direzioni, con i contatori, così potete capire se la regola ha mai corrisposto:

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'

Una regola con un contatore di pacchetti a zero non è nel percorso. O i nomi delle interfacce differiscono da quelli che avete supposto, o una regola precedente nella catena ha accettato, scartato o restituito il pacchetto per prima. Correggete l’ordine, non il testo della regola.

Il traffico di risposta è la metà che la gente dimentica. La regola di ritorno ha bisogno dello stesso nome veth più una corrispondenza di stato della connessione, o di una semplice accettazione dell’interfaccia se tenete la politica aperta. Aggiungete solo la regola in uscita e il sintomo originale torna, con la vostra nuova regola lì che sembra corretta.

Tenete le regole di marcatura del tunnel lontane dal nuovo percorso

Questo passo trasforma uno spazio dei nomi funzionante in uno che perde. Le installazioni WireGuard di solito installano una politica di marcatura del firewall insieme alle proprie regole di routing e a una tabella dedicata, così i pacchetti non marcati ricadono sulla tabella principale mentre quelli marcati usano la tabella del tunnel. Il traffico inoltrato dallo spazio dei nomi viene valutato rispetto al routing basato su policy in uscita e, a seconda di come sono scritte quelle regole, può finire nella tabella del tunnel.

Due aggiunte separano i percorsi. Tornate presto nella catena mangle per la sottorete dello spazio dei nomi e aggiungete una regola basata sull’origine che mette quella sottorete nella tabella 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 si ordina prima delle regole del tunnel sul mio host, quindi per quell’origine decide la tabella normale. Non copiate il numero alla cieca: le priorità che wg-quick installa differiscono tra versioni e tra le configurazioni IPv4 e IPv6, quindi eseguite ip rule show e scegliete una priorità che cada davanti alle regole del tunnel sulla vostra macchina.

Verificate con una ricerca specifica per l’origine invece di fidarvi dell’elenco delle regole:

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

Se il primo comando riporta l’interfaccia WireGuard, la nuova regola non è ancora davanti alla politica del tunnel. Se riporta l’interfaccia WAN mentre il secondo mostra ancora la rotta predefinita veth, l’host e lo spazio dei nomi non concordano e dovreste rileggere entrambe le tabelle di routing.

Avviate il processo che apre la connessione

Avviare il comando è una riga, ma avviate il processo che crea davvero il socket.ip netns exec clearnet curl -s https://ifconfig.me è il test onesto più piccolo: mostra l’indirizzo che lo spazio dei nomi presenta al mondo, non quello che userebbe l’host.

Per un servizio, collegate lo spazio dei nomi tramite percorso così il processo vi rimane per tutta la sua vita:

[Service]
NetworkNamespacePath=/run/netns/clearnet

Le applicazioni grafiche sono dove l’approccio a una riga fallisce silenziosamente. Un browser avviato da un menu spesso consegna la richiesta a un’istanza che gira già fuori dallo spazio dei nomi, così la nuova finestra appare e il traffico esce ancora dal tunnel. Datele un profilo separato perché venga davvero creata una nuova istanza, poi controllate il contesto del processo invece di indovinare:

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

I due output devono coincidere. Lo stesso controllo funziona per qualsiasi programma di lunga durata, e vale la pena farlo una volta per applicazione invece di dare per scontato che il launcher abbia fatto quello che volevate.

La risoluzione dei nomi richiede una decisione propria. Creare uno spazio dei nomi non gli dà una configurazione del resolver; i file per spazio dei nomi sono supportati tramite /etc/netns/<name>/resolv.conf e senza uno ereditate un comportamento facile da leggere male. IPv6 richiede lo stesso trattamento: se lo spazio dei nomi non ha una rotta predefinita v6 mentre l’applicazione preferisce v6, le richieste possono bloccarsi prima di ripiegare, il che sembra un tunnel rotto.

Controllate l’inquadratura, non solo l’indirizzo di uscita

Un indirizzo pubblico funzionante dimostra la rotta, non l’intero requisito. Percorrete il resto in questo ordine:

  • ip netns exec clearnet ip route get 1.1.1.1 mostra la rotta predefinita veth, non l’interfaccia WireGuard.
  • I contatori FORWARD su entrambe le regole aumentano mentre una richiesta è in corso.
  • Il processo dell’applicazione riporta l’inode dello spazio dei nomi che vi aspettate.
  • Dopo un riavvio lo spazio dei nomi esiste prima che il servizio parta; un’unità che parte prima fallisce o, peggio, gira fuori dallo spazio dei nomi.

Poi decidete cosa deve succedere quando il tunnel cade. Lo spazio dei nomi continua a funzionare, che è lo scopo dell’esercizio e anche il rischio: il programma esentato resta connesso mentre tutto il resto si ferma. Registratelo come scelta di politica e siate chiari su ciò che l’esenzione non copre — l’identità dell’account, lo stato salvato del browser e il vostro provider DNS stanno tutti fuori dall’ambito di uno spazio dei nomi di rete, e trattare l’esenzione come anonimato è l’errore che sopravvive alla configurazione.

Articoli correlati