Qual è il costo di molti TIME_WAIT sul lato server?

Supponiamo che ci sia un client che crea molte connessioni di breve durata con un server.

Se il client chiude la connessione, ci saranno molte porte nello stato TIME_WAIT sul lato client. Poiché il client esaurisce le porte locali, diventa imansible effettuare rapidamente un nuovo tentativo di connessione.

Se il server chiude la connessione, vedrò molte TIME_WAIT sul lato server. Tuttavia, questo fa male? Il client (o altri client) può continuare a eseguire i tentativi di connessione poiché non ha mai terminato le porte locali e il numero di TIME_WAIT aumenterà sul lato server. Cosa succede alla fine? Succede qualcosa di brutto? (rallentamento, arresto anomalo, connessioni interrotte, ecc.)

Tieni presente che la mia domanda non è “Qual è lo scopo di TIME_WAIT ?” ma “Cosa succede se ci sono così tanti stati TIME_WAIT sul server?” So già cosa succede quando una connessione viene chiusa in TCP / IP e perché è richiesto lo stato TIME_WAIT . Non sto cercando di risolvere il problema, ma voglio solo sapere qual è il potenziale problema con esso.

Per netstat -nat | grep :8080 | grep TIME_WAIT | wc -l , diciamo netstat -nat | grep :8080 | grep TIME_WAIT | wc -l netstat -nat | grep :8080 | grep TIME_WAIT | wc -l netstat -nat | grep :8080 | grep TIME_WAIT | wc -l stampa 100000 . Cosa succederebbe? Lo stack di rete O / S rallenta? Errore “Troppi file aperti”? O, niente di cui preoccuparsi?

Ogni socket in TIME_WAIT consuma memoria nel kernel, in genere un po ‘meno di un socket ESTABLISHED ma ancora significativo. Un numero sufficientemente grande potrebbe esaurire la memoria del kernel, o almeno peggiorare le prestazioni perché tale memoria potrebbe essere utilizzata per altri scopi. TIME_WAIT socket TIME_WAIT non contengono i descrittori di file aperti (supponendo che siano stati chiusi correttamente), quindi non dovresti preoccuparti di un errore “troppi file aperti”.

Il socket collega anche quel particolare indirizzo IP e porta src / dst modo che non possa essere riutilizzato per la durata dell’intervallo TIME_WAIT . (Questo è lo scopo previsto dello stato TIME_WAIT .) Sollevare la porta di solito non è un problema a meno che non sia necessario riconnetterlo con la stessa coppia di porte. Molto spesso una parte usa una porta effimera, con solo una parte ancorata a una porta ben nota. Tuttavia, un numero molto elevato di socket TIME_WAIT può esaurire lo spazio di porta temporaneo se si verificano ripetutamente e frequentemente la connessione tra gli stessi due indirizzi IP. Nota questo riguarda solo questa particolare coppia di indirizzi IP, e non influenzerà la creazione di connessioni con altri host.

Risultati finora:

Anche se il server ha chiuso il socket utilizzando la chiamata di sistema, il relativo descrittore di file non verrà rilasciato se entra nello stato TIME_WAIT. Il descrittore di file verrà rilasciato in seguito quando lo stato TIME_WAIT sarà scomparso (ovvero dopo 2 * secondi MSL). Pertanto, troppe TIME_WAITs porteranno probabilmente all’errore “troppi file aperti” nel processo del server.

Credo che lo stack TCP / IP di O / S sia stato implementato con una struttura dati adeguata (es. Tabella hash), quindi il numero totale di TIME_WAITs non dovrebbe influire sulle prestazioni dello stack TCP / IP O / S. Ne risentirà solo il processo (server) che possiede i socket nello stato TIME_WAIT.

Ogni connessione è identificata da una tupla (IP del server, porta del server, IP del client, porta del client). Fondamentalmente, le connessioni TIME_WAIT (sia che si trovino sul lato server o sul lato client) occupano ciascuna una di queste tuple.

Con TIME_WAIT sul lato client, è facile capire perché non è ansible effettuare altre connessioni: non ci sono più porte locali. Tuttavia, lo stesso problema si verifica sul lato server – una volta che ha 64k connessioni nello stato TIME_WAIT per un singolo client , non può accettare altre connessioni da quel client , perché non ha modo di distinguere la vecchia connessione e la nuova connessione: entrambe le connessioni sono identificate dalla stessa tupla. In questo caso, il server dovrebbe semplicemente inviare indietro i RST ai nuovi tentativi di connessione da quel client.

Se disponi di molte connessioni da molti IP client diversi agli IP del server, potresti incontrare limitazioni della tabella di tracciamento delle connessioni.

Dai un’occhiata:

 sysctl net.ipv4.netfilter.ip_conntrack_count sysctl net.ipv4.netfilter.ip_conntrack_max 

Su tutte le tuple ip / port e dest ip / port di src puoi solo avere net.ipv4.netfilter.ip_conntrack_max nella tabella di monitoraggio. Se viene raggiunto questo limite, nei registri verrà visualizzato un messaggio “nf_conntrack: tabella completa, eliminazione del pacchetto”. e il server non accetterà nuove connessioni in entrata finché non ci sarà di nuovo spazio nella tabella di tracciamento.

Questa limitazione potrebbe colpirti molto prima che le porte effimere si esauriscano.

Nel mio scenario ho eseguito uno script che pianifica ripetutamente i file, il mio prodotto esegue alcuni calcoli e invia una risposta al client, ad esempio il client sta effettuando una ripetuta chiamata http per ottenere la risposta di ogni file. Quando circa 150 file sono programmati, le porte socket nel mio server vanno nello stato time_wait e viene generata un’eccezione nel client che apre una connessione http ie

  Error : [Errno 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted 

Il risultato è stato che la mia applicazione è stata bloccata. Non so se i thread sono andati in stato di attesa o cosa è successo, ma ho bisogno di uccidere tutti i processi o riavviare la mia applicazione per farlo funzionare di nuovo.

Ho provato a ridurre il tempo di attesa a 30 secondi poiché è 240 secondi per impostazione predefinita, ma non ha funzionato.

Quindi l’impatto generale è stato fondamentale poiché ha reso la mia applicazione non retriggers

sembra che il server possa esaurire le porte per assegnare le connessioni in entrata (per la durata dei TIMED_WAIT esistenti) – un caso per un attacco DOS.