Una via d’uscita da questa workstation è un proxy SOCKS, e OpenVPN dietro di esso segnala un timeout di connessione senza nulla di utile. Un browser sulla stessa macchina funziona attraverso quel proxy, le credenziali sono corrette e la porta risponde. Tre cose differiscono abbastanza spesso da verificarle per prime: la versione SOCKS parlata dal proxy, il trasporto scelto dal client e dove avviene la risoluzione dei nomi. Conferma ciascuna di esse prima di decidere che il firewall è la causa.

Allinea la versione SOCKS prima del firewall

OpenVPN community parla SOCKS5 per socks-proxy. Puntalo su un proxy che offre solo SOCKS4: la connessione TCP si apre e poi si blocca, perché il client attende una risposta a un saluto che l’altro capo non analizza mai. Dall’esterno quel blocco sembra esattamente una porta filtrata, ed è per questo che la questione della versione viene prima di qualsiasi regola del firewall. Una richiesta consapevole di SOCKS lo risolve con un solo comando.

curl --socks5-hostname 127.0.0.1:9050 gw.lab.example

Una richiesta completata dimostra due cose insieme: il proxy ha accettato la richiesta SOCKS e ha risolto il nome. Non serve alcuno schema URL, perché curl tratta un host nudo come HTTP, il che basta per questo test.

Quella richiesta esclude anche il guasto che il log del client nasconde. Un proxy può consentire il browser e rifiutare comunque la destinazione VPN, e in quel caso il rifiuto avviene al CONNECT, prima di qualsiasi autenticazione VPN. OpenVPN segnala solo un timeout, quindi la risposta del proxy stesso è la prova che ti serve.

Il trasporto deve essere TCP su entrambi i lati

SOCKS5 trasporta qui un flusso TCP, quindi il tunnel stesso richiede proto tcp-client. Un profilo ancora impostato su UDP non funzionerà su questo percorso, perché il client non usa la modalità di associazione UDP del protocollo. Cambiare il profilo è una modifica reale e non una formalità: l’altro capo deve ascoltare su TCP sulla stessa porta. Il carico diventa allora TCP dentro TCP, dove un segmento perso viene ritrasmesso due volte e il ritmo peggiora, cosa che le sessioni interattive notano molto più dei trasferimenti grandi.

proto tcp-client
remote gw.lab.example 8443
socks-proxy 127.0.0.1 9050

La direttiva accetta l’host del proxy, una porta opzionale e un file di credenziali opzionale. Mettili nel profilo stesso, così una copia si comporta allo stesso modo altrove.

Confina l’intera catena in un solo container

Fare la catena sull’host significa prendere la sua rotta predefinita e lasciare il resolver in uno stato che nessuno saprà spiegare in seguito. Un namespace o un container la delimita invece, così l’host conserva il proprio percorso mentre il salto SOCKS e il tunnel vivono insieme. Lì dentro non sale nulla senza un dispositivo di tunnel, i permessi per configurarlo e un proxy raggiungibile. Un servizio Compose lo ottiene con cap_add: NET_ADMIN e un /dev/net/tun montato in bind.

cap_add:
  - NET_ADMIN
devices:
  - /dev/net/tun:/dev/net/tun

Questa coppia è più stretta dell’eseguire il container con privilegi, ed è tutto l’accesso al dispositivo necessario. Un client Tor o un container proxy separato può fornire l’ascoltatore. In entrambi i casi legalo al loopback e raggiungilo dal namespace attraverso l’host invece di esporre il proxy alla rete.

La risoluzione dei nomi è dove l’isolamento fallisce

Un tunnel che trasporta pacchetti mentre interroga il resolver dell’host non ha isolato nulla. Due cose rendono reale l’isolamento: il namespace ha un resolver proprio e le sue query viaggiano attraverso il proxy o il tunnel, mai sull’interfaccia fisica. Usa due nomi per il test: uno che esiste solo dietro il tunnel e uno pubblico che dovrebbe seguire lo stesso percorso.

docker compose exec vpn cat /etc/resolv.conf
docker compose exec vpn getent hosts internal.lab.example

Se il nome remoto si risolve e quello pubblico no, la catena è selettiva e non rotta, e la differenza ti dice quale percorso ha preso ogni query. Se entrambi si risolvono dall’host ma nessuno dentro il container, il container sta ancora prendendo in prestito il resolver dell’host. Annota il file di resolver trovato, perché è l’impostazione da cambiare.

Dimostra ogni salto in ordine

La lista è breve. Una richiesta SOCKS5 ottiene risposta, il tunnel raggiunge il suo ascoltatore attraverso il proxy e i pacchetti che escono dal namespace portano l’indirizzo che l’altro capo si aspetta. Conferma ognuno singolarmente invece di stratificare altra configurazione. Quando il client dice connesso e nulla si muove, la rottura è quasi sempre nel secondo o nel terzo fatto.

curl --socks5-hostname 127.0.0.1:9050 gw.lab.example
docker compose exec vpn ip route get 203.0.113.10
docker compose exec vpn getent hosts internal.lab.example

Annota la combinazione che ha funzionato: versione SOCKS, trasporto, resolver e impostazioni del namespace. Risolvere questa catena una seconda volta a memoria costa più della nota. Tieni quei quattro fatti nel ticket invece che in un thread di chat.

Una catena che riporta connesso e non fa passare nulla di solito ha fallito al salto che non hai ancora dimostrato. Prova quel salto prima di aggiungere un altro strato.

Articoli correlati