Due gateway, una VPN: perché OpenVPN sceglie il collegamento in uscita sbagliato
Il tunnel va bene; il socket esce dal WAN sbagliato. Leggi l'indirizzo del peer attivo, fissa una rotta host e controlla prima le regole di policy.
Due collegamenti in uscita, un tunnel, e il traffico esce da quello che non hai scelto. Le sottoreti private sono raggiungibili, il log segnala una connessione riuscita, ed è il collegamento misurato a trasportarlo. Nulla nell'output di OpenVPN menziona un gateway, perché il client non ne ha mai scelto uno. Ha aperto un socket verso un indirizzo remoto e ha lasciato che il kernel decidesse come raggiungerlo.
L'indirizzo del tunnel non è l'endpoint
In ogni sessione esistono due percorsi diversi. Il percorso esterno trasporta il traffico cifrato fino all'indirizzo pubblico del server. Il percorso interno trasporta tutto ciò che il server spinge nel tunnel, e le regole di instradamento di uno non hanno effetto sull'altro.
La voce remote del profilo indica la destinazione esterna, quindi è quello l'indirizzo da fissare. È anche il valore che cambia quando un nome host si risolve diversamente o il profilo elenca più remote.
Trova l'indirizzo che il client ha realmente chiamato
Leggi il socket attivo invece del file di configurazione. La tabella dei socket mostra il peer a cui il processo si è realmente connesso, ed è il valore che l'eccezione deve raggiungere. Un profilo può essere modificato dopo l'inizio della sessione, e il socket è l'unica prova di ciò che è stato chiamato:
ss -tunp | grep -i openvpn
journalctl -u openvpn-client@work --no-pager | grep -i "Peer Connection Initiated"
La riga di log indica l'indirizzo e la porta del peer al momento della connessione. Se non coincide con il profilo, qualcosa davanti al client riscrive la destinazione prima che la connessione inizi.
Controlla anche la famiglia di indirizzi. Un profilo dual-stack può connettersi via IPv6 mentre l'eccezione copre solo IPv4, e allora il traffico segue una regola diversa da quella che hai scritto. Lo stesso vale per un proxy che risponde per conto dell'endpoint. Entrambi i casi producono un tunnel che funziona mentre la tua rotta non fa nulla.
Fissa l'endpoint e leggi l'ordine delle policy
Una rotta host è più specifica di qualsiasi rotta predefinita. Per questo una /32 per l'indirizzo del peer vince dentro la tabella che la contiene. La forma abituale indica esplicitamente il gateway e il dispositivo:
ip route add 203.0.113.40/32 via 192.168.10.1 dev eth0
Quella rotta aiuta solo se la ricerca raggiunge quella tabella. Le regole di policy vengono valutate in ordine e la prima corrispondenza decide, quindi una regola che manda tutto in una seconda tabella aggira la tua rotta host in main. Leggi le regole prima di dare per scontato che la rotta faccia fede:
ip rule show
ip route get 203.0.113.40
Interroga il secondo comando con lo stesso indirizzo sorgente o marchio che il client usa quando la policy dipende da essi. Riporta la rotta che il kernel sceglierebbe, il che è una prova sulla ricerca e non la prova che il socket attivo usi quel percorso.
Quando l'endpoint si sposta
Un nome host che si risolve in più indirizzi invalida una /32 permanente non appena la risposta cambia. Un profilo con più righe remote ha lo stesso problema, perché il client può atterrare su una qualsiasi. Aggiorna la rotta dagli hook del ciclo di vita del client stesso invece di aggiungerla a mano. Uno script up che legge il peer negoziato e installa la rotta host mantiene l'eccezione allineata alla realtà, e uno script down corrispondente la rimuove.
Registra l'aggiornamento nello stesso punto del resto della configurazione di instradamento dell'host. Una rotta che esiste solo fino al prossimo riavvio è un test, non una correzione.
Tieni separata la policy interna
Spostare il percorso esterno non dà accesso a una nuova sottorete privata e non cambia quali destinazioni il server spinge nel tunnel. La rotta dello strato inferiore sceglie il cavo; le rotte spinte scelgono cosa entra nel tunnel. Tenere separate queste due decisioni è ciò che rende prevedibile la separazione.
Se l'obiettivo è solo tenere il traffico cifrato fuori da un collegamento misurato, lascia stare la rotta predefinita e aggiungi l'unica eccezione host. Sostituire la rotta predefinita dell'intera macchina per spostare una sola connessione VPN rompe ogni altra applicazione sull'host.
Conferma il risultato con due osservazioni indipendenti: l'indirizzo locale e il dispositivo del socket, e la rotta verso cui si risolve la destinazione privata. Quando entrambe corrispondono alla tua intenzione, la separazione è reale. Il manuale di OpenVPN 2.6 copre le opzioni remote e di binding locale che decidono a quale indirizzo il client si connette.