GNU/Linux >> Znalost Linux >  >> Linux

Problémy s frontou TIME_WAIT

Nedávno jsme popsali, jak nakonfigurovat váš server pro vysokou zátěž a prevenci DDoS. Dnes budeme mluvit o problémech s frontou time_wait. Ti, kteří vyvíjejí služby aktivně pracující se sítí, mohou využít vlastnosti protokolu TCP:přechod mnoha (nebo všech volných) portů do stavu TIME_WAIT. Na internetu je spousta povrchních informací a spousta ne zcela správných informací. Zvážíme, o jaké situace jde, a určíme možná východiska z nich.

Protokol TCP:připojení ukončeno

Následuje typický diagram životního cyklu připojení TCP:

Schéma životnosti TCP

Nebudeme to brát jako celek, ale zaměříme se na pro nás nejdůležitější část – uzavření spojení. Strana, která iniciovala uzavření spojení, se nazývá „aktivní“ a druhá – je „pasivní“. A je jedno, kdo z nich byl iniciátorem spojení.

Z „pasivní“ strany je vše jednoduché. Po přijetí paketu FIN by na něj měl systém odpovědět příslušným ACK paketem, ale má právo pokračovat v odesílání dat. Od přijetí paketu FIN je připojení na pasivní straně ve stavu CLOSE_WAIT. Když je připraven, odešle se paket FIN s odpovědí, načež strana čeká na ACK paket. Po přijetí ACK do odpovědi FIN je spojení pro pasivní stranu uzavřeno.

Z pohledu „aktivní“ strany je vše poněkud složitější. Po odeslání paketu FIN aktivní strana zadá FIN_WAIT_1. Dále jsou možné tři situace:

  1. Přijmout ACK na paket FIN. Tento stav je indikován FIN_WAIT_2, data mohou být doručena straně, poté je očekáván paket odpovědi FIN, na který aktivní strana odpoví ACK a uvede spojení do stavu TIME_WAIT.
  2. Pokud je pasivní strana připravena ukončit relaci, může být odpověď FIN přijata se současným ACK na původní paket FIN. V tomto případě aktivní strana odpoví potvrzením ACK a přenese spojení na TIME_WAIT, přičemž obejde FIN_WAIT_2.
  3. Je možná situace, kdy strany současně zahájily uzavření. V tomto případě jsou obě strany „aktivní“, na obou stranách se připojení přepne do stavu TIME_WAIT.

Jak je patrné z diagramu a popisu, aktivní strana odešle poslední paket v relaci (ACK do pasivního FIN). Protože nemůže zjistit, zda byl tento paket přijat, stav je TIME_WAIT. V tomto stavu by spojení mělo být 2 * MSL (maximum packet lifetime):čas doručení paketu na pasivní stranu + čas doručení případného paketu odpovědi zpět. V praxi je v současnosti časovač TIME_WAIT nastaven na 1 – 2 minuty. Po vypršení tohoto časovače je připojení považováno za uzavřené.

TIME_WAIT potíže s odchozím připojením

Připojení v operačním systému je identifikováno čtyřmi parametry:local IP, local port, remote IP, remote port. Předpokládejme, že máme klienta, který se aktivně připojuje/odpojuje ke vzdálené službě. Protože IP i vzdálený port zůstávají nezměněny, je pro každé nové připojení přidělen nový místní port. Pokud byl klient aktivní stranou konce relace TCP, bude toto připojení na chvíli zablokováno ve stavu TIME_WAIT. Pokud jsou připojení navázána rychleji než karanténa portů, pak při příštím pokusu o připojení klient obdrží chybu EADDRNOTAVAIL (errno =99).

I když aplikace přistupují k různým službám a nedojde k chybě, fronta TIME_WAIT poroste a zabere systémové prostředky. Připojení ve stavu TIME_WAIT lze zobrazit pomocí netstat, je vhodné se podívat na zobecněné informace pomocí nástroje ss (s klávesou -s).

Co se dá dělat:

  • Interval TIME_WAIT systému Linux nelze změnit bez překompilování jádra. Na internetu lze najít odkazy na parametr net.ipv4.tcp_fin_timeout se zněním „v některých systémech ovlivňuje TIME_WAIT“. Co však tyto systémy jsou, není jasné. Podle dokumentace parametr určuje maximální dobu čekání na paket FIN s odpovědí, tj. omezuje dobu strávenou připojením ve FIN_WAIT_2, nikoli však TIME_WAIT.
  • Otevřete méně připojení. Chyba je nejčastěji pozorována během síťové interakce v rámci clusteru. V tomto případě by použití Keep-Alive bylo moudrým rozhodnutím.
  • Při navrhování služby může mít smysl posunout TIME_WAIT na druhou stranu, kvůli čemuž bychom se měli, pokud je to možné, zdržet uzavírání spojení TCP.
  • Pokud je obtížné snížit počet připojení, pak má smysl spustit vzdálenou službu na několika portech a postupně k nim přistupovat.
  • Parametr jádra „net.ipv4.ip_local_port_range“ nastavuje rozsah portů používaných pro odchozí připojení. Větší dosah – více připojení k jedné vzdálené službě.
  • Náročný a extrémně nebezpečný způsob:snižte hodnotu parametru net.ipv4.tcp_max_tw_buckets na hodnotu nižší, než je počet IP adres v rozsahu od ip_local_port_range. Tento parametr nastavuje maximální velikost fronty TIME_WAIT a používá se k ochraně před útoky DOS. Tento „trik“ lze dočasně použít, dokud nebude vyvinuto správné řešení.
  • Povolte parametr net.ipv4.tcp_tw_reuse. Tento parametr umožňuje použití připojení ve stavu TIME_WAIT pro odchozí připojení.
  • Povolte parametr net.ipv4.tcp_tw_recycle.
  • Použijte režim SO_LINGER (nastavený pomocí setsockopt). V tomto případě nebude TCP relace uzavřena (výměna FIN paketů), ale zahozena. Strana, která si přeje provést reset, odešle RST paket. Po přijetí tohoto paketu se spojení považuje za ukončené. Podle protokolu by však mělo být odesílání paketu RST provedeno pouze v případě chyby (přijetí dat, která zjevně nesouvisí s tímto připojením).

TIME_WAIT na serverech

Hlavním nebezpečím, že se fronta TIME_WAIT na serveru rozšíří, je nedostatek zdrojů.

Přesto může docházet k nepříjemným incidentům při práci s klienty NAT (když je za jednou IP umístěno velké množství serverových klientů). V případě krátké doby karantény portu na bráně firewall je pravděpodobné, že server obdrží požadavek na připojení ze stejného portu, se kterým spojení ještě není uzavřeno (nachází se v TIME_WAIT). V tomto případě jsou možné dva až tři scénáře:

  • (nepravděpodobný) zákazník uhodne číslo SEQ, což je vysoce nepravděpodobné. V tomto případě je chování nedefinované.
  • Klient odešle paket s nesprávným (z pohledu serveru číslem SEQ), na který server odpoví posledním ACK paketem, kterému klient již nerozumí. Klient obvykle odešle RST na toto ACK a čeká několik sekund před pokusem o nové připojení. Pokud je parametr „net.ipv4.tcp_rfc1337“ na serveru zakázán (ve výchozím nastavení vypnutý), bude nový pokus úspěšný. Především z důvodu časového limitu však bude pozorován pokles výkonu.
  • Pokud je v situaci popsané na str. 2 povolen parametr net.ipv4.tcp_rfc1337, server bude ignorovat paket RST klienta. Opakované pokusy o připojení k serveru ze stejného portu selžou. Pro klienta se služba stane nedostupnou.

Co lze udělat na straně serveru.

  1. Zkuste posunout zahájení ukončení připojení ke klientovi. Přitom musí být nastaveny přiměřené časové limity.
  2. Buďte opatrní s parametrem net.ipv4.tcp_max_tw_buckets. Nastavení příliš velké způsobí, že server bude zranitelný vůči útoku DOS.
  3. Pro zjevně nesprávné dotazy použijte SO_LINGER. Pokud se klient připojí a pošle „nesmysl“, pak je pravděpodobné, že došlo k útoku, na který je lepší utratit minimální množství prostředků.
  4. Povolte net.ipv4.tcp_tw_recycle, pokud jste si jisti, že klienti neprocházejí NAT. Je důležité si uvědomit, že net.ipv4.tcp_tw_reuse neovlivňuje zpracování příchozích připojení.
  5. V některých případech má smysl s frontou „nebojovat“, ale správně ji distribuovat. Pomoci mohou zejména následující recepty:
    • Při použití balanceru L7 pocházejí všechny pakety ze stejné IP adresy, což vyvolává „zásahy“ ve spojení TIME_WAIT, ale v tomto případě můžete bezpečně povolit tcp_tw_recycle.
    • Při použití balanceru L3 server vidí zdrojové IP adresy. Vyvažování IP-HASH zároveň přepošle všechna spojení pro jeden NAT na jeden server, což také zvyšuje pravděpodobnost kolize. Round-Robin je v tomto ohledu spolehlivější.
    • Pokud je to možné, nepoužívejte NAT uvnitř sítě. V případě potřeby je lepší upřednostnit překlad 1 v 1.
    • Počet dostupných připojení můžete zvýšit hostováním služby na několika portech. Například u WEB serveru může být zátěž vyvážena nikoli na jednom 80. portu, ale na skupině portů.
  6. Pokud je problém způsoben NAT uvnitř sítě, můžete situaci vyřešit překonfigurováním překladu na síťovém zařízení:je nutné zajistit, aby doba „karantény“ portu na NAT byla delší než TIME_WAIT. Ale v tomto případě se zvyšuje riziko, že na překladači NAT dojde k vyčerpání portů (volitelně se překlad neprovádí na jednu IP, ale do fondu).

Parametry jádra net.ipv4.tcp_tw_reuse a net.ipv4.tcp_tw_recycle

V jádře Linuxu jsou dva parametry, které vám umožňují porušit požadavky protokolu TCP a uvolnit připojení z TIME_WAIT s předstihem. Obě tyto možnosti jsou založeny na rozšíření TCP-timestamps (označení paketů relativními časovými razítky).

net.ipv4.tcp_tw_reuse umožňuje použít připojení v TIME_WAIT pro nové odchozí připojení. V tomto případě by nové časové razítko TCP spojení mělo být o řád větší než poslední hodnota v předchozí relaci. V tomto případě bude server schopen rozlišit „opožděný“ paket z předchozího připojení od aktuálního. Použití parametru je ve většině případů bezpečné. Problémy mohou nastat, pokud je podél cesty „sledovací“ firewall, který se rozhodne nezmeškat paket ve spojení, což by mělo být v TIME_WAIT.

net.ipv4.tcp_tw_recycle snižuje dobu připojení ve frontě TIME_WAIT na hodnotu RTO (Re-Transmission Time-Out), která se vypočítává na základě Round-Trip-Time (RTT) a rozpětí této hodnoty. Současně je v jádře uložena poslední hodnota TCP-timestamp a pakety s nižší hodnotou jsou jednoduše zahozeny. Tato volba způsobí, že služba nebude dostupná pro klienty za NAT, pokud jsou TCP-časová razítka od klientů „přeskočena“ během překladu (pokud je NAT odstraní nebo je nahradí vlastními, nenastanou žádné problémy). Vzhledem k tomu, že není možné předvídat nastavení externích zařízení, tuto možnost důrazně nedoporučujeme zahrnout na servery přístupné z Internetu. Navíc na „interních“ serverech, kde není NAT (nebo se používá možnost 1 v 1), je tato možnost bezpečná.


Linux
  1. Ssh – pomocí již zavedeného kanálu Ssh?

  2. Jak přidat vzdálené připojení MySQL v linuxu?

  3. Metody připojení MySQL

  1. Testování síťových služeb pomocí Netcat

  2. Příklady příkazů připojení iSCSI (cheat Sheet)

  3. Jak úplně zničit připojení zásuvky v C

  1. Linux – Detekce připojení/odpojení sluchátek v Linuxu?

  2. komár-klient získat odmítnuté připojení

  3. 2 tiskárny 1 fronta