I sintomi seguono un’unica forma: un host funziona, poi si connette a una VPN come client, e ora i client LAN lo raggiungono mentre le sue risposte svaniscono. Una cattura sull’host mostra che le risposte escono dal dispositivo del tunnel invece che dall’interfaccia LAN. Nulla del tunnel è rotto, e la correzione è una rotta, non una riconnessione. Seguite i quattro controlli qui sotto in ordine e fermatevi al primo che fallisce.

Una risposta è un nuovo pacchetto, non un’inversione

Aiuta abbandonare l’idea che una risposta torni lungo il percorso che ha seguito una richiesta. L’instradamento si decide per pacchetto, per direzione, sull’host che invia. Una richiesta arrivata da 10.64.0.23 dentro il tunnel non crea alcun percorso di ritorno; quando l’host risponde, quella risposta viene confrontata con la tabella come un pacchetto nuovo ed esce dalla rotta che vince.

Per questo un client a tunnel completo su una macchina che serve anche una LAN produce un guasto così confuso. Il client installa una rotta predefinita, o le due semirotte predefinite che alcuni client preferiscono, e la risposta a un client LAN ora corrisponde al tunnel. Va al fornitore, che non ha motivo di inoltrarla, e il client LAN vede un timeout nonostante un host attivo che risponde localmente. La cattura lo rende evidente, e la tabella di instradamento lo spiega.

Tenete due sottoreti in mente mentre leggete il resto. Una è il pool di indirizzi VPN da cui arrivano i client remoti, in questo esempio 10.64.0.0/24. L’altra è la LAN che deve continuare a funzionare, 172.16.24.0/24 con il suo router su 172.16.24.1. Il bug è che il traffico tra le due è deciso dalla rotta predefinita.

Dimostratelo con la cattura e la ricerca

Prima di cambiare qualcosa, confermate quale dispositivo userà la risposta. Una ricerca è più rapida di una cattura e risponde esattamente alla domanda a cui risponderà il kernel quando il pacchetto viene costruito.

ip route get 10.64.0.23 from 172.16.24.10
tcpdump -ni any -c 6 icmp

Leggete la risposta in due parti. Se nomina dev tun0, l’host incapsulerà la risposta e la consegnerà al fornitore, e il client LAN non la vedrà mai. Se nomina dev eth0 ma il client va ancora in timeout, la rotta è già corretta e il pacchetto viene scartato più tardi, che è un altro problema con un’altra correzione.

La cattura nello stesso passaggio risolve il dubbio che un ping non può. Un eco di risposta che arriva al client LAN dimostra che qualche percorso funziona, non quale interfaccia l’ha portato, quindi eseguite la cattura sull’host stesso e osservate da dove escono i frame. Una stampante sulla stessa sottorete continua a rispondere, perché la sua rotta diretta è più specifica della rotta predefinita del tunnel. Una porta inoltrata fallisce esattamente come qualsiasi altro flusso, perché la tabella sceglie l’interfaccia e la connessione no.

Installate la rotta più specifica che supera il tunnel

Decide la lunghezza del prefisso, non la metrica, quindi una rotta per il pool di client attraverso il router LAN vince su qualsiasi rotta predefinita installata dal client VPN. Nessuna chirurgia della metrica è necessaria, e la rotta predefinita può restare esattamente dove il client l’ha messa.

ip route replace 10.64.0.0/24 via 172.16.24.1 dev eth0
ip route get 10.64.0.23 from 172.16.24.10

Usate replace invece di add, perché un client che si riconnette avrà installato la propria voce e un secondo add fallisce con un errore di rotta esistente che si legge come un problema di permessi. Su un host Windows l’equivalente è route add 10.64.0.0 mask 255.255.255.0 172.16.24.1 -p, dove -p conserva la voce tra i riavvii, dato che il client può ricostruire la tabella quando il tunnel torna su. Su un host Windows attuale l’equivalente supportato è New-NetRoute -DestinationPrefix 10.64.0.0/24 -NextHop 172.16.24.1 -InterfaceAlias Ethernet -PolicyStore PersistentStore, con il comando route più vecchio mantenuto come forma legacy.

Un dettaglio decide se questo è corretto o solo plausibile: il prossimo salto deve essere il router che possiede davvero il percorso di ritorno ai client. Puntare la rotta a un indirizzo che è a sua volta raggiunto attraverso il tunnel crea un ciclo che si manifesta come perdita intermittente invece che come guasto netto. Confermate che il prossimo salto è sulla sottorete LAN prima di confermare la riga.

Mantenete la risposta dopo una riconnessione

Una rotta aggiunta a mano sopravvive al massimo fino alla riconnessione successiva. Se il pool di client è dinamico, fissatelo nella configurazione del server così che il prefisso che avete instradato resti il prefisso che i client ricevono; altrimenti la voce punta a un intervallo vuoto e il sintomo torna settimane dopo senza causa evidente. Scrivere la rotta nello script up del client stesso è l’altra opzione affidabile, perché viene eseguito dopo che il client ha riscritto la tabella.

Un firewall stateful può ancora sconfiggere una rotta corretta. Se la cattura ora mostra che la risposta esce da eth0 e il client va ancora in timeout, controllate se l’host scarta il pacchetto prima di inviarlo. Il filtro rigoroso del percorso inverso e net.ipv4.conf.all.rp_filter impostato a 1 scartano i pacchetti la cui origine non sarebbe instradata di ritorno dall’interfaccia da cui sono arrivati, che è esattamente il caso asimmetrico appena creato e poi corretto, e lo stato di conntrack racconta la stessa storia per le porte inoltrate.

L’ultimo controllo è quello che la gente salta: ripetete la ricerca dopo che il tunnel è stato giù e poi su. Quattro valori devono corrispondere a quelli annotati: la destinazione, il prossimo salto, il dispositivo e l’origine scelta. Se uno di essi si è spostato, il client ha riscritto la tabella e la correzione appartiene ai suoi hook e non alla cronologia di una shell.

Articoli correlati