Il kill switch si attiva: cosa succede alle sessioni TCP aperte?
Un pacchetto bloccato non è una connessione chiusa. Decidete se una sessione deve sopravvivere all’interruzione, poi mettete alla prova blocco e ripristino come proprietà separate.
Il tunnel cade, il kill switch si attiva e un download arrivato a tre quarti si blocca oppure fallisce subito. Questi due esiti derivano da scelte di applicazione diverse, non da livelli di protezione diversi. Un pacchetto scartato lascia la connessione in attesa, mentre uno rifiutato la chiude e avvisa l’applicazione. Decidere quale comportamento si vuole è una questione di progettazione, e provarlo è un esercizio a parte.
Scartare, rifiutare e resettare sono cose diverse
Una regola del firewall che scarta il traffico elimina il pacchetto e non restituisce nulla, quindi il mittente continua a ritrasmettere con i propri timer. Una regola che rifiuta con un TCP reset chiude subito la connessione e l’applicazione vede un errore. La maggior parte dei kill switch scarta, perché un rifiuto rivelerebbe la politica e perché lo scarto assomiglia al comportamento di una rete morta.
Bloccare non è lo stesso che chiudere il socket. L’applicazione tiene ancora un descrittore in stato stabilito e mancano solo i pacchetti. Per questo una pagina può restare su un indicatore di caricamento per minuti mentre il sistema operativo insiste che la connessione esiste. Leggete la politica di applicazione documentata invece di dedurla dal messaggio dell’applicazione, dato che entrambi i comportamenti sembrano una rete caduta.
Che cosa fa l’applicazione mentre dura l’interruzione
TCP ritrasmette con ritardi crescenti, e il budget di tentativi predefinito di Linux scade intorno a un quarto d’ora, non in secondi. Fino ad allora il socket non è né utilmente aperto né chiuso. Le applicazioni con keepalive o timeout delle richieste propri spesso si arrendono prima, ed è per questo che due programmi sulla stessa macchina si comportano in modo diverso durante un’interruzione.
Quando il tunnel torna, il socket locale è invariato ma il percorso può non esserlo. Un nuovo indirizzo sorgente pubblico produce una quadrupla diversa sul server, quindi un firewall con stato sul lato remoto non corrisponde più alla sessione. La connessione è morta anche se il client non ha mai visto un errore.
Decidete se il ripristino è necessario
Scegliete tra due contratti. O la sessione deve sopravvivere a una breve interruzione, il che richiede indirizzamento stabile e un server che conservi il proprio stato, oppure l’applicazione deve riconnettersi in modo pulito, il che richiede una logica di tentativi sicura da ripetere. Qualsiasi via di mezzo produce il risultato peggiore: un client che reinvia ciò che il server ha già registrato, o uno che dichiara successo per una sessione che nessuno può vedere.
L’indirizzamento stabile è la parte che si dimentica, perché una riconnessione che atterra su un indirizzo pubblico diverso invalida lo stato lato server anche quando il socket del client sembra sano. Annotate quale dei due contratti vale per ogni applicazione, dato che raramente coincidono tutti.
Verificate il blocco e il ripristino separatamente
Trattate la protezione dalle perdite e la sopravvivenza della sessione come due proprietà, perché superarne una non dice nulla sull’altra. Una sessione che sopravvive non è prova che il traffico diretto sia stato bloccato, e una sessione che muore non è prova che ogni rotta diretta lo sia stata.
ss -tnp state established '( dport = :443 )'
sudo conntrack -L -p tcp --dport 443
sudo tcpdump -ni any 'tcp port 443 and tcp[tcpflags] & tcp-syn != 0'
Usate un’operazione di test innocua quando osservate il ripristino, così un invio duplicato non diventi l’incidente. Registrate la modalità di guasto che avete visto davvero: cosa mostrava l’applicazione, se il socket è sopravvissuto e quando si è ripreso da solo.
Scrivete il comportamento atteso accanto alla regola di applicazione e datatelo. La prossima persona che cambierà quella regola deve sapere quale dei due contratti ha promesso la distribuzione.