Niente nel socket ricorda quale interfaccia ha trasportato la richiesta, quindi una rotta predefinita VPN a tunnel completo può catturare una risposta che appartiene alla WAN. Il servizio non ignora l’interfaccia in ingresso; Linux instrada una risposta generata localmente in base alla destinazione e alla politica di origine. Una regola basata sull’origine può invece inviare solo le risposte del servizio attraverso una tabella WAN completa, lasciando l’uscita ordinaria sul tunnel. La porta resta aperta mentre la risposta esce dal percorso sbagliato, ed è per questo che il sintomo sembra unilaterale.

L’equivoco: le risposte seguono l’interfaccia da cui sono arrivate

Sembra logico che un pacchetto in arrivo su eth0 debba uscire su eth0. I filtri di pacchetti senza stato possono essere scritti così, e tcpdump sul lato in ingresso mostra la richiesta esattamente dove ci si aspetta. L’instradamento non funziona così per il traffico che l’host stesso origina.

Una volta che il servizio accetta la connessione, la sua risposta è un nuovo pacchetto generato localmente. Il kernel consulta le regole di instradamento per la destinazione e l’origine della risposta, e la rotta predefinita della VPN è una risposta del tutto valida. Niente nel socket ricorda quale interfaccia ha trasportato la richiesta.

Per questo il sintomo sembra unilaterale: le richieste arrivano, le risposte svaniscono. Per questo anche aggiungere una regola del firewall per la porta in ingresso non cambia nulla. Il pacchetto non viene bloccato all’andata; viene instradato altrove al ritorno. Seguite la risposta con una ricerca qualificata per origine e la deviazione diventa visibile.

Che cosa instrada davvero il kernel: l’indirizzo di origine

La maniglia che serve è l’indirizzo locale che il servizio usa per le risposte. Su un host con l’indirizzo eth0 illustrativo 192.0.2.10/24 e il gateway 192.0.2.1, quell’indirizzo è presente sull’interfaccia. Su una VM nel cloud l’indirizzo pubblico può essere tradotto a monte e assente nell’ospite, quindi usate l’indirizzo che l’host possiede davvero.

Ispezionate lo stato attuale prima di riservare un numero di tabella o una priorità di regola. Le regole di policy esistenti possono oscurarne una nuova, e una vecchia tabella con lo stesso numero può già portare rotte non correlate:

ip -4 addr show dev eth0
ip -4 rule show
ip -4 route show table all

Poi selezionate una tabella per origine. La regola corrisponde alle risposte che già portano 192.0.2.10, esattamente il traffico terminato localmente che volete esentare. Il traffico inoltrato e i pacchetti da altri indirizzi locali non corrispondono.

Costruite una tabella di ritorno completa, non mezza rotta predefinita

Una tabella con sola rotta predefinita non basta. Il kernel deve comunque risolvere il gateway, e quella risoluzione richiede il prefisso connesso nella stessa tabella. Una tabella priva di quel prefisso fallisce nella risoluzione del gateway anche quando la sua rotta predefinita sembra corretta. Aggiungete entrambe, poi puntate la regola di origine alla tabella:

ip -4 route add table 100 192.0.2.0/24 dev eth0 src 192.0.2.10
ip -4 route add table 100 default via 192.0.2.1 dev eth0
ip -4 rule add priority 1000 from 192.0.2.10/32 lookup 100

Usate il prefisso e il gateway reali invece di copiare l’esempio. Un’interfaccia cloud configurata come /32 con un gateway on-link richiede una rotta connessa diversa, e una tabella costruita dal prefisso sbagliato fallisce al primo salto. L’attributo src indica l’origine preferita per quella rotta; non sostituisce la regola di origine.

Anche l’ordine conta. Una regola ampia con un numero di priorità più basso viene valutata per prima, quindi la regola di origine deve essere raggiunta prima di qualsiasi regola che rimanderebbe questo traffico alla tabella principale. Controllate le priorità con ip rule show dopo averla aggiunta, non solo all’avvio.

Verificate con una ricerca qualificata per origine

Chiedete al kernel di instradare una destinazione di prova dall’indirizzo del servizio. La risposta dovrebbe nominare eth0 e il gateway WAN, non il tunnel:

ip -4 route get 198.51.100.25 from 192.0.2.10

Poi stabilite una nuova connessione autorizzata e osservate entrambe le direzioni. Una ricerca che seleziona la tabella giusta mentre la connessione reale fallisce ancora indica il filtraggio del percorso inverso o una regola del firewall, non la tabella. Controllate quei controlli prima di disattivare qualcosa globalmente.

Mettete le rotte finali e la regola sotto il gestore di rete che possiede l’interfaccia. I cambi di indirizzo, il rinnovo DHCP e le riconnessioni VPN riscrivono tutti lo stato del kernel, e una regola aggiunta a mano scompare o punta a un gateway obsoleto dopo l’evento successivo.

Dove si ferma questa eccezione

La regola esenta il traffico terminato localmente da un indirizzo di origine. Non copre le porte pubblicate da Docker, il DNAT o i servizi inoltrati attraverso l’host, perché quei pacchetti sono instradati come traffico inoltrato e non portano mai l’origine locale dell’host allo stesso modo. Tali progetti richiedono di solito un marchio impostato in ingresso e una regola che corrisponda al marchio.

Non fa nemmeno comparire l’indirizzo pubblico dell’host sull’interfaccia. Quando un NAT a monte possiede quell’indirizzo, la risposta deve comunque uscire dal percorso che quel NAT si aspetta, ed è per questo che la tabella WAN deve rispecchiare il gateway e il prefisso originali invece di un intervallo pubblico indovinato.

Mantenete l’eccezione documentata con il numero di tabella, la priorità della regola e l’indirizzo di origine esatto. Il prossimo cambiamento alla VPN o all’interfaccia può romperla in silenzio, e una nota che nomina i tre valori è più rapida da controllare che riscoprire il sintomo da un rapporto del cliente.

Se il servizio risponde ancora sul percorso sbagliato dopo che la ricerca qualificata per origine è passata, confrontate l’indirizzo di origine del socket attivo con quello nella regola. Un servizio legato a un indirizzo jolly può scegliere un’origine diversa dall’indirizzo che avete testato, e quella discrepanza è il divario rimanente.

Articoli correlati