Stavové sledování spojení (connection tracking)

Omezení a výkon

Tabulka spojení, kterou udržuje conntrack představuje poměrně složitou datovou strukturu, ve které se potenciálně vyhledává příslušný záznam pro každý zpracovávaný packet. To samo o sobě už je dost velký problém, protože si vezměme, že na 1Gb/s Ethernetu může přijít za sekundu přes 1,4 milionu packetů (když uvažujeme nejkratší možné IP datagramy). Na 10Gb/s, je to pak přes 14 milionů packetů za sekundu.

Aby toho nebylo málo, musí se pro každé nově otevřené spojení a každou novou UDP relaci udělat zápis do tabulky spojení a stejně tak pro každé skončené spojení a nebo zaniklou relaci se musí udělat výmaz. Linux momentálně používá kombinaci hashovací tabulky a linked-listu jako datovou strukturu pro udržování tabulky spojení a to samo o sobě znamená, že změny se musí částečně chránit lockem a snižují tedy multi-threadovou propustnost (byť i to se snaží autoři Netfilteru minimalizovat).

V neposlední řadě samo uložení tabulky v paměti zabírá prostor a to je pochopitelně docela odlišný problém na serveru s mnoha desítkami GB paměti a na SOHO routeru s 64 MB RAM. Linux má pro conntrack několik sysctl parametrů, kde tím nejzajímavějším je omezení na maximální počet záznamů v tabulce spojení - ve výpisu jej vidíme i s výchozí hodnotou:

root@r1:~/# sysctl net.netfilter.nf_conntrack_max
net.netfilter.nf_conntrack_max = 262144

V principu na normálně zatížené pracovní stanici, serveru a nebo domácím routeru vám bude pravděpodobně 256 k spojení stačit. Nicméně pokud Linux použijete jako firewall pro firmu z několika desítkami souběžně pracujících uživatelů, může se vám snadno stát, že v součtu tento limit překročí. Opravdu: jsou webové aplikace, které navazují stovky spojení s různými CDN servery, ze kterých pak sestavují Javascriptem výslednou stránku a tato spojení klidně drží desítky minut, dokud má uživatel záložku s danou stránkou otevřenou. Stačí, aby si několik desítek uživatelů spustilo několik desítek těchto aplikací, které navazují stovky spojení a k limitu se dostanete snadno. K tomu si uvědomte, že nesprávně ukončená spojení vám v tabulce zůstávají několik minut do timeoutu.

Krom toho samotný conntrack je docela lákavým cílem pro útoky odepřením služby (DoS) a vskutku se občas potkávají. Je ale diskutabilní, jesti tyto volumetrické útoky, které otevírají mnoho spojení, cílí na conntrack, na aplikace nebo na zastaralé síťové stacky. Každopádně pokud se tabulka spojení zaplní, vede to k tomu, že firewall nová spojení nepřijímá a zahazuje jejich packety. Dobrá zpráva je, že o tom píše docela jasnou zprávu do dmesg. Špatná zpráva je, že si toho těžko všimnete dřív, než vám začnou chodit stížnosti uživatelů, ledaže sledujete přes nějaký monitoring zaplnění tabulky z parametru net.netfilter.nf_conntrack_count a máte dobře nastavené alarmy.

Tím se tedy dostáváme k poslední úvaze: Conntrack je sice dobrý sluha, ale zlý pán. V některých situacích je výhodné vystačit si s bezstavovými pravidly a conntrack buď úplně vypnout. Případně jej lze vypnout selektivně pro konkrétní provoz pomocí zvláštního targetu NOTRACK, které lze použít v tabulce raw v chainu PREROUTING. Toto selektivní vypnutí conntracku má smysl například pro autortiativní DNS servery pro provoz na port 53/udp, který je beztak zpravidla tvořen pouze dvojicemi otázka a odpověď.