Un server VPN che risponde da una rete mobile e fallisce dal divano di solito non è un problema di certificato. Il client dentro la LAN chiede al router di tradurre un pacchetto la cui destinazione è l'indirizzo pubblico del router stesso, il che significa che il pacchetto deve uscire e rientrare subito. Questa manovra si chiama hairpinning, e molti router o non la implementano o la fanno solo quando è attiva una casella. È il successo del test da fuori che rende la cosa confusa, perché dimostra che il listener e la regola di inoltro sono a posto.

Il pacchetto esce e rientra

Seguite il pacchetto. Il client risolve il nome pubblico, si connette all'indirizzo pubblico, e il NAT di destinazione del router riscrive la destinazione verso il server interno. La risposta del server è indirizzata all'indirizzo LAN del client, quindi torna indietro attraverso l'interfaccia LAN del router senza mai attraversare la regola NAT che avrebbe ritradotto la sorgente.

Ora il client riceve un pacchetto da un indirizzo a cui non ha mai inviato nulla, e lo scarta. Questa asimmetria è tutta l'avaria.

La RFC 4787 descrive il comportamento atteso da un NAT in questo caso, e la versione breve è che in pratica è facoltativo anche dove è specificato in teoria. Alcuni router chiamano l'impostazione NAT loopback, altri hairpin NAT o NAT reflection, e alcuni non espongono nulla. Un router che ne è privo non è mal configurato; fa la cosa normale, e la correzione appartiene altrove. Non concludete da un test locale fallito che la regola di inoltro pubblica sia sbagliata.

Verifica 1: provate i due percorsi separatamente

Da fuori della LAN, connettetevi con lo stesso profilo che userebbe un utente reale e confermate che la sessione si stabilisce. Da dentro, connettetevi all'indirizzo pubblico con lo stesso profilo e annotate l'errore esatto e l'ora.

Un test locale preciso conserva il nome host e sostituisce solo l'indirizzo: curl -v --resolve vpn.example.com:443:203.0.113.10 https://vpn.example.com/ invia la richiesta all'indirizzo pubblico presentando comunque il nome server corretto. Questo separa un problema di risoluzione dei nomi da un problema di traduzione, facili da confondere quando lo stesso nome funziona da un bar. Annotate se il client fallisce nella connessione TCP o più tardi in TLS, perché il primo indica la traduzione e il secondo l'identità.

Verifica 2: leggete ciò che vede il server

L'osservazione più utile è la vista del server. Avviate una cattura sull'host VPN filtrata sull'indirizzo LAN del client e su quello LAN del router, poi ripetete il tentativo locale. Se non arriva nulla, il pacchetto non è sopravvissuto alla traduzione.

Se una connessione arriva dall'indirizzo LAN del router invece che da quello del client, l'hairpinning sta avvenendo e la sorgente è stata riscritta. È una configurazione funzionante, non un guasto.

Verifica 3: correggete senza toccare il percorso esterno

Esistono tre forme supportate, in ordine crescente di raggio d'azione. La più stretta è il DNS diviso: pubblicate un record interno così che lo stesso nome server risolva all'indirizzo interno per i client della LAN, il che evita del tutto il percorso pubblico. La successiva è abilitare l'opzione documentata di loopback o reflection del router, se esiste, e applicarla solo a questo servizio. La più ampia è una regola source-NAT sul router che riscrive il traffico proveniente dalla LAN verso il server perché la risposta torni attraverso il router; su un router Linux è una regola MASQUERADE in POSTROUTING che corrisponde all'indirizzo e alla porta del server. Tutte e tre lasciano intatto il percorso esterno, ed è questa la proprietà da preservare.

Non ampliate un inoltro di porta non correlato per far somigliare il percorso locale a quello esterno, e non spostate il servizio su un'altra porta per aggirare il problema. Entrambe le modifiche cambiano ciò che il mondo esterno può raggiungere per correggere qualcosa che solo il mondo interno vede.

Il DNS diviso ha una trappola che vale la pena nominare. Sostituire un nome host con un IP arbitrario cambia ciò che il client convalida, quindi il record interno deve comunque corrispondere al nome del certificato.

Verifica 4: verificate entrambi i percorsi dopo

Ripetete il tentativo esterno da fuori della LAN, ripetete il tentativo interno con lo stesso profilo, e confermate che il log del server mostri due sessioni riuscite distinte invece di un successo e un silenzio. Poi verificate che gli altri client raggiungano ancora il listener e che le rotte verso le risorse private siano invariate.

Tenete il verbale breve: quale indirizzo ha usato ogni client, cosa ha visto il server e quale delle tre correzioni è stata applicata. I requisiti di hairpinning della RFC 4787 sono il riferimento per ciò che ci si aspetta da un NAT qui, e spiegano perché un router privo della funzione si comporta normalmente. Un guasto locale che il mondo esterno non riesce a riprodurre è una questione di traduzione finché non si dimostri il contrario, quindi provatelo come tale.

Articoli correlati