Il tunnel completo di OpenVPN tronca la sessione SSH: correggi il percorso di ritorno
La rotta predefinita manda le risposte SSH nel tunnel. Fissa il peer, filtra redirect-gateway o instrada per sorgente prima di perdere la macchina.
Attivare un client OpenVPN in tunnel completo su una macchina raggiunta via SSH può troncare la sessione in un secondo, e la macchina non sta facendo nulla di sbagliato. Il tunnel non cambia come i pacchetti raggiungono il server; cambia come escono le risposte. Appena la rotta predefinita punta a tun0, una risposta al tuo client SSH entra nella rete del provider, che non ha una rotta di ritorno verso il tuo indirizzo. La connessione si blocca, il tentativo successivo va in timeout e il demone continua ad ascoltare sulla porta 22 per tutto il tempo.
Leggi la tabella di routing prima di leggere il log del VPN. Il log dirà che il tunnel è salito, e ha ragione. La domanda è a quale interfaccia viene consegnata ogni risposta, e questa è una ricerca per pacchetto in una tabella che il tunnel ha appena riscritto.
Perché la risposta esce dalla porta sbagliata
I pacchetti in entrata arrivano ancora sull'interfaccia fisica, perché un client VPN non può cambiare come internet raggiunge l'indirizzo pubblico del tuo server. Le risposte sono una decisione separata: per ogni pacchetto il kernel cerca la destinazione, e dopo --redirect-gateway la voce predefinita dice tunnel. L'uscita del provider vede una destinazione che non serve e scarta il pacchetto.
La protezione propria di OpenVPN copre esattamente una destinazione. Il manuale della 2.6 descrive --redirect-gateway come una sequenza: aggiunge una rotta host per il peer VPN attraverso il gateway in uso prima del tunnel, così il traffico cifrato non può tornare dentro se stesso, poi sostituisce la rotta predefinita. Quella rotta host è solo per il peer. Il tuo client SSH è solo un altro indirizzo internet e non riceve alcuna eccezione.
Vale la pena escludere subito un errore di prefisso. ip route add -net 0.0.0.0 gw 10.8.0.1 dev tun0 senza lunghezza corrisponde all'indirizzo singolo 0.0.0.0, non a internet; deve essere 0.0.0.0/0. E se prendere la rotta predefinita rompe il trasporto del tunnel stesso, aggiungi l'endpoint come rotta host attraverso l'interfaccia fisica, usando l'indirizzo reale del provider.
Fissa l'indirizzo del tuo client SSH per una riparazione immediata
La riparazione più rapida è una rotta host per l'indirizzo del tuo client attraverso il gateway che il server usava prima che esistesse il tunnel. Dal tuo lato, trova l'indirizzo che il server vedrà, poi leggi la tabella del server per conoscere il vecchio gateway:
curl -s https://ifconfig.co
ip route
Sul server, aggiungi l'eccezione prima che il client parta. Gli indirizzi qui sono segnaposto; la forma è ciò che conta:
sudo ip route add 80.128.240.55 via 192.168.178.1
Questa è la riparazione usata nel caso segnalato, e funziona subito. È anche fragile in due modi prevedibili: la rotta sparisce al riavvio e diventa sbagliata nel momento in cui il tuo ISP ti assegna un altro indirizzo. Trattala come misura d'emergenza e rendila duratura di proposito, tramite un'unità di rete o un hook del dispatcher, oppure accetta che sia temporanea e annota il percorso di ripristino.
Impedisci al client di prendere la rotta predefinita
L'opzione più pulita è impedire al tunnel di sostituire del tutto la rotta predefinita. route-nopull, usato con --client o --pull, accetta le opzioni inviate tranne le rotte, block-outside-dns e le opzioni in stile DHCP come i server DNS, quindi aggiungi solo i prefissi che ti servono. Uno strumento più stretto è un filtro di pull, che scarta una direttiva problematica e tiene il resto:
route-nopull
pull-filter ignore "redirect-gateway"
Usa l'uno o l'altro, non entrambi, e sii chiaro su cosa cambia. Senza rotta predefinita attraverso il tunnel, il server non naviga più internet tramite il provider; raggiunge solo ciò che hai instradato esplicitamente. Se il tunnel completo era l'intero scopo della configurazione, questa è la leva sbagliata e la rotta host sopra è quella giusta.
Dividi il percorso di ritorno per sorgente o per connessione
Quando l'indirizzo in entrata è stabile, una regola di sorgente tiene le risposte in locale senza toccare le rotte del tunnel stesso. Dai all'indirizzo dell'interfaccia fisica una sua tabella con il prefisso LAN e la rotta predefinita fisica, poi seleziona quella tabella per il traffico che ne proviene:
ip rule add from 192.168.1.11 table 128
ip route add table 128 to 192.168.1.0/24 dev eth0
ip route add table 128 default via 192.168.1.1
Questo funziona perché le risposte a una connessione SSH in entrata provengono dall'indirizzo a cui il client si è connesso. Un caso segnalato in cui ogni servizio in entrata doveva continuare a funzionare usava esattamente questa forma. Quando l'indirizzo in entrata è mobile o il percorso è dinamico, contrassegna invece la connessione: metti un marchio conntrack sul primo pacchetto che arriva dall'interfaccia fisica, copialo sui pacchetti di risposta in OUTPUT e instrada i pacchetti contrassegnati attraverso una tabella che punta al gateway fisico.
iptables -t mangle -A PREROUTING -i eth0 -m conntrack --ctstate NEW -j CONNMARK --set-mark 1234
iptables -t mangle -A OUTPUT -m connmark --mark 1234 -j MARK --set-mark 4321
ip route add default via 192.168.1.1 dev eth0 table 3412
ip rule add fwmark 4321 table 3412
Tieni distinti il marchio di connessione, il marchio del firewall e il numero di tabella durante i test. Riusare un solo numero per due ruoli produce una regola che sembra corretta e colpisce i pacchetti sbagliati. Anche la voce predefinita della tabella richiede via con il gateway LAN su un normale collegamento Ethernet; una voce dev eth0 nuda funziona solo quando l'interfaccia è punto a punto o il salto successivo viene risolto in un altro modo. L'host Jessie segnalato si trovava su un collegamento dove la forma nuda funzionava, che non è una regola di distribuzione da copiare.
Verifica senza chiuderti fuori
Non testare disconnettendoti. Tieni aperta la prima sessione, alza il tunnel e chiedi al kernel quale percorso prenderebbe il tuo indirizzo:
ip route get 80.128.240.55
La risposta dovrebbe nominare l'interfaccia fisica e il vecchio gateway, non il tunnel. Poi apri una seconda connessione SSH; quella è la prova vera, perché la sessione vecchia può sopravvivere su uno stato che una nuova connessione non può riprodurre. Se la seconda si blocca mentre la prima risponde ancora, la regola non ha mai incontrato il traffico che conta, e i marchi o l'indirizzo di origine sono il punto da guardare.
Tieni disponibile una console fuori banda per tutto l'esercizio. Un server il cui unico percorso di accesso è il tunnel che hai appena rotto non si può riparare attraverso quel tunnel, e il rollback è più facile quando hai annotato i numeri di tabella e i prefissi che hai aggiunto.