Anche un portatile dietro il NAT dell'operatore può servire un collega, purché il server VPN faccia da punto d'incontro. Due meccanismi ci arrivano: il client si collega verso l'esterno e chiede al server di tenere una porta in ascolto, oppure il server pubblica una porta e la traduce dentro il tunnel. Entrambi risolvono lo stesso problema di raggiungibilità e si comportano diversamente in caso di guasto, supervisione e registrazione. Tre condizioni decidono quale appartiene alla vostra configurazione.

Due forme, un punto d'incontro

Nella prima forma il client apre una sessione SSH verso l'esterno e chiede al server di ascoltare su una porta scelta, rinviando ogni connessione attraverso quella sessione. Sul server non viene inoltrato nulla e non avviene alcuna traduzione di pacchetti, quindi gli unici requisiti sono un account SSH, un inoltro consentito e una regola del firewall per la porta. Il servizio resta legato al loopback sul client, che di solito è ciò che si desidera.

ssh -N -R 8081:127.0.0.1:8080 -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 [email protected]

Nella seconda forma il server possiede la porta pubblica e riscrive ogni connessione verso l'indirizzo del tunnel del client. Ciò richiede l'inoltro IP attivo, una traduzione di destinazione in ingresso e una traduzione di origine in uscita, e continua a funzionare quando non esiste alcuna sessione SSH. La porta appartiene al server e non a una sessione, ed è questa proprietà a decidere la maggior parte dei casi reali.

Nessuna delle due forme è più sicura per costruzione. Entrambe finiscono per esporre una porta di servizio a chiunque possa raggiungere l'indirizzo pubblico del server, ed entrambe dipendono ancora dall'autenticazione propria del servizio.

Condizione uno: la porta deve sopravvivere alla sessione

Un inoltro inverso vive esattamente quanto la sessione SSH che lo ha creato. Quando il collegamento cade, l'ascoltatore scompare e il collega vede una connessione rifiutata invece di un percorso lento. Sorvegliare il comando con un'unità systemd e una politica di riavvio risolve, e ExitOnForwardFailure=yes rende subito visibile un binding fallito invece di lasciare una sessione che gira senza inoltro.

Una porta tradotta sopravvive ai riavvii se le regole sono persistenti, ma dipende dal fatto che il client mantenga lo stesso indirizzo del tunnel. Un pool dinamico che assegna al portatile un altro indirizzo dopo la riconnessione punta la regola in silenzio verso il nulla. Prenotate prima l'indirizzo del tunnel, poi scrivete la regola, e trattate i due come un'unica modifica.

Se il servizio deve rispondere alle tre di notte senza nessuno che guardi, la forma con la porta pubblicata dal server ha meno parti mobili, perché l'unico processo che deve restare in piedi è il tunnel stesso.

Condizione due: chi possiede il firewall e i registri

La forma inversa tiene tutta la politica in due punti. sshd decide se gli inoltri remoti sono consentiti del tutto tramite AllowTcpForwarding, e GatewayPorts decide se l'ascoltatore si lega al loopback o a ogni indirizzo. Con il valore predefinito no un collega fuori dal server non raggiunge la porta anche se l'inoltro è riuscito, e questo sembra un tunnel rotto quando in realtà è un indirizzo di binding.

sudo ss -ltn '( sport = :8081 )'
sudo grep -E '^(GatewayPorts|AllowTcpForwarding)' /etc/ssh/sshd_config

La forma tradotta richiede l'inoltro attivo e due regole, e la seconda regola è dove sbagliano la maggior parte delle ricette. Limitare la traduzione di origine allo stato conntrack DNAT significa che vengono riscritte solo le connessioni create dalla regola di destinazione, invece di ogni pacchetto che il server manda nel tunnel.

sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8081 -j DNAT --to-destination 10.88.0.6:8080
sudo iptables -t nat -A POSTROUTING -o tun0 -m conntrack --ctstate DNAT -j SNAT --to-source 10.88.0.1

Quella riscrittura distrugge anche l'attribuzione. Dopo, il client vede ogni chiamante come l'indirizzo del tunnel del server, il che fa collassare qualsiasi limite di velocità per indirizzo in un unico secchio e nasconde chi ha inviato cosa. Se l'attribuzione conta, terminate la connessione sul server o tenete lì la decisione di autorizzazione e passate un'identità in un'intestazione di cui il servizio si fida. Scegliere tra queste due correzioni dipende dal fatto che il servizio legga o meno un'intestazione proxy.

Condizione tre: una porta o molte, e chi possiede il nome

Un solo servizio su una sola porta è il caso in cui l'inoltro inverso vince per impegno. Serve un comando, un account e una regola del firewall, e la pulizia è uccidere la sessione. Più servizi sullo stesso indirizzo pubblico spingono verso la forma pubblicata dal server, perché ogni inoltro inverso ha bisogno della propria porta server e l'insieme cresce con ogni servizio.

I nomi complicano ulteriormente. Un inoltro inverso può stare dietro a un proxy TCP che instrada per SNI, mentre una porta tradotta è di solito una porta per servizio. Se il servizio termina il TLS da solo e ha bisogno del nome host originale, l'approccio proxy lo preserva e l'approccio DNAT lo preserva solo se il servizio accetta quel nome su quella porta.

Annotate quale delle tre condizioni ha deciso la forma. Altrimenti la prossima persona che aggiungerà un secondo servizio riaprirà lo stesso confronto con meno contesto.

Decidete, poi provate dall'esterno

Provate il percorso da una rete che non ha alcuna rotta verso il portatile, e osservate i contatori sul server mentre la richiesta è in corso. Provare dal server verso il proprio indirizzo pubblico non dimostra nulla qui, perché il pacchetto viene creato localmente e non raggiunge mai l'hook di traduzione in ingresso, quindi il test può passare mentre il percorso reale è rotto.

sudo iptables -t nat -L PREROUTING -n -v
sudo tcpdump -ni any 'tcp port 8081' -c 20

Contatori che restano piatti significano che il pacchetto non è mai arrivato alla regola, il che punta al provider o al firewall dell'host. Contatori che si muovono mentre il servizio rifiuta puntano al firewall del client o all'indirizzo su cui il servizio ascolta. Un tunnel che trasporta il pacchetto ma non restituisce nulla è un problema di rotta o di percorso inverso, e nessuno di questi tre esiti dovrebbe essere diagnosticato modificando l'adattatore del client. Annotate quale contatore si è mosso prima di cambiare qualcosa, perché il test successivo ha bisogno di quella linea di base.

Quando la forma funziona, registrate la porta, il proprietario e il metodo di supervisione accanto alla configurazione del tunnel. Una correzione di raggiungibilità che esiste solo nella cronologia della shell di qualcuno è a un riavvio da un incidente ripetuto.

Articoli correlati