I client si connettono e si autenticano, poi il loro traffico esce dal collegamento in salita sbagliato, perché l’unica rotta predefinita sulla macchina appartiene al gateway stesso. Sostituire quella rotta predefinita romperebbe gli aggiornamenti e l’accesso di gestione della macchina, quindi la selezione deve essere più stretta di «tutto il traffico». La forma che funziona è una regola di policy basata sull’indirizzo sorgente interno del pool di client, che punta a una seconda tabella di routing che possiede il WAN alternativo. Da lì in poi la lista di controllo riguarda completezza e comportamento in caso di guasto, non la regola in sé.

Verificate che l’indirizzo sorgente sopravviva fino alla decisione di routing

Una regola di policy che corrisponde a un intervallo sorgente scatta solo quando il pacchetto porta ancora quella sorgente al momento della ricerca. Il traffico dei client inoltrato lo fa, finché nulla a monte lo ha riscritto prima del routing. Il traffico generato dal gateway non lo fa, ed è proprio per questo che la sua rotta predefinita può restare dov’è.

Qui i test locali ingannano. Un curl eseguito sul gateway è un flusso generato localmente con l’indirizzo del gateway, quindi prende la tabella principale e non dimostra nulla sul percorso del client. Provate da un client connesso, o generate traffico con una sorgente che appartenga davvero al pool.

Iniziate scrivendo i valori reali: il prefisso del pool, l’interfaccia di tunnel che lo trasporta, l’indirizzo e il next hop del secondo WAN, e il numero di tabella che intendete usare. Cancellate le vecchie regole di ogni tentativo precedente prima di aggiungerne di nuove, perché regole duplicate con priorità diverse producono guasti che sembrano casuali.

Costruite una tabella selezionata che sia completa

Una tabella non è una rotta predefinita con un amico. Le servono abbastanza rotte perché ogni ricerca si risolva al suo interno, compresa la rotta connessa della sottorete WAN perché il next hop sia raggiungibile. Per un pool 10.77.0.0/24 su tun1, un indirizzo WAN 203.0.113.20/24 con next hop 203.0.113.1, e la tabella 600:

ip -4 route replace 203.0.113.0/24 dev usb0 src 203.0.113.20 table 600
ip -4 route replace 10.77.0.0/24 dev tun1 table 600
ip -4 route replace default via 203.0.113.1 dev usb0 table 600
ip -4 rule add priority 1500 from 10.77.0.0/24 lookup 600

La regola sta a una priorità inferiore a qualsiasi regola catch-all esistente, quindi i client corrispondenti raggiungono prima la tabella 600 e tutto il resto ricade nella tabella principale. Il riferimento di ip-rule descrive per intero il modello di ricerca ordinata e la sintassi del selettore.

Poi pensate a ciò che la tabella non contiene. Una destinazione che ha rotta solo nella tabella principale, come una sottorete di gestione raggiungibile via eth0, non verrà trovata nella tabella 600 e non ricadrà sulla principale una volta che lì esista una rotta predefinita. Se quei percorsi contano, aggiungeteli esplicitamente alla tabella selezionata, che di solito è la risposta giusta per una tabella di uscita VPN.

Tenete il traffico dell’ascoltatore fuori dalla policy

L’ascoltatore OpenVPN ha una propria connessione esterna, trasportata sul collegamento in salita con cui il client lo ha raggiunto. Quel traffico deve conservare il percorso di ritorno con cui è arrivato, e una regola ampia che copra l’indirizzo pubblico del server o l’intera interfaccia di tunnel può trascinarlo nella tabella alternativa. Limitate la regola al pool interno e a nient’altro.

Il filtro sul percorso inverso merita uno sguardo per lo stesso motivo. Quando le risposte ai client escono da usb0 mentre la richiesta è arrivata su un altro collegamento, un’impostazione rp_filter rigida può scartare pacchetti che la policy di routing considera validi. Controllate i valori sysctl effettivi su entrambe le interfacce prima di concludere che la regola ha fallito.

Anche l’ordine conta rispetto a tutto il resto sulla macchina. I bridge Docker, un secondo VPN e qualsiasi regola preesistente di un’immagine del provider aggiungono priorità, quindi leggete l’elenco completo delle regole invece di dare per scontato che la priorità 100 sia sola.

Fate concordare inoltro e traduzione con la rotta

Il routing sceglie un collegamento in salita; non concede il permesso di inoltrare. Il kernel deve avere l’inoltro IPv4 abilitato, e il firewall deve accettare la direzione dal client al WAN e il traffico di ritorno. Una tabella corretta con una catena FORWARD che scarta il flusso produce lo stesso sintomo di una rotta mancante, per questo entrambi vengono controllati nello stesso passaggio.

Se il secondo WAN non instraderà un pool privato verso di voi, traducete la sorgente su quell’uscita. Per un’interfaccia con indirizzo dinamico, la scelta abituale è una regola masquerade stretta limitata al pool e all’interfaccia:

iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -o usb0 -j MASQUERADE

Qui l’ambito conta più del bersaglio. Una regola masquerade che corrisponde a qualsiasi interfaccia in uscita riscriverà anche il traffico che esce correttamente da eth0, e questo nasconde gli errori di routing invece di correggerli. La traduzione gira dopo la decisione di routing, quindi non può mai riparare un pacchetto inviato al collegamento in salita sbagliato.

Anche l’overhead del tunnel richiede attenzione quando i percorsi differiscono. Se i client negoziano un MSS TCP grande e il WAN alternativo ha un MTU più basso o un tunnel al suo interno, i segmenti grandi si bloccano mentre quelli piccoli funzionano. Il clamping dell’MSS sul percorso di inoltro lo trasforma in un comportamento prevedibile invece di un blocco intermittente.

Decidete cosa succede quando usb0 scompare

Una tabella vuota non è uno stato di chiusura in caso di guasto. Se la rotta corrispondente scompare, la ricerca prosegue verso la regola successiva, raggiunge la tabella principale e prende la rotta predefinita di eth0. Il traffico che doveva uscire dal secondo WAN esce silenziosamente dal primo, il che in un deployment con routing basato su policy è di solito il risultato che volete meno.

Dove quel ripiego è inaccettabile, aggiungete una rotta terminale esplicita nella tabella 600, come una rotta predefinita blackhole, oppure scartate il pool nel firewall mentre l’interfaccia è giù. Entrambe sono decisioni che potete scrivere; il silenzio no.

La persistenza è l’ultimo punto. Chi possiede entrambi i collegamenti, che sia il gestore di rete, uno script dispatcher o il ciclo di vita della connessione, deve ricreare le rotte e la regola a ogni riconnessione senza aggiungere duplicati. Verificate con una richiesta da un client reale e una richiesta separata dal gateway, confermate l’uscita osservata su entrambi, poi staccate il secondo WAN e guardate quale dei due esiti che avete progettato si verifica davvero. IPv6 ha bisogno della propria tabella, regola e traduzione; la regola IPv4 sopra non dice nulla al riguardo.

Articoli correlati