SACK, czyli selektywne potwierdzenia pakietów

Spis treści

Protokół TCP jest tak zbudowany by zapewnić rzetelny transfer danych między dwoma komunikującymi się punktami. Z początku jednak, ta cecha tego protokołu powodowała marnowanie dość sporych ilości zasobów jeśli chodzi o przepustowość łącza. Stało się to widoczne przy większych prędkościach połączeń, gdzie skalowany był bufor (okno) TCP, co umożliwiło przesyłanie szeregu segmentów bez potrzeby czekania na ich potwierdzenie przez odbiorcę. To zwiększyło, co prawda, transfer danych ale pojawił się problem z zagubionymi pakietami.

Zwykły ACK

Gdy pakiet nie dociera do odbiorcy, to po pewnym czasie zostaje retransmitowany. Co się jednak dzieje w przypadku wysłania na drugą stronę 100 segmentów? Jeśli zagubieniu ulegnie, dajmy na to, trzeci z nich, to trzeba retransmitować 3,4-100. Mimo, że pakiety 4-100 trafiły do odbiorcy. Mało tego, w sytuacji zgubienia się pakietu numer 3 i po dotarciu wszystkich następnych, odbiorca musi wysłać zduplikowane pakiety ACK sygnalizując problem z jednym z wcześniejszych pakietów. Tych duplikatów byłoby 98. Ten proces został zobrazowany poniżej (źródło):

retransmisja-pakietow-ack

Niezła rozrzutność i tu właśnie w grę wchodzi mechanizm SACK, czyli selektywny ACK.

SACK

Jak zatem wyglądałaby powyżej opisana sytuacja po zaimplementowaniu mechanizmu SACK? Popatrzmy na kolejną fotkę (źródło):

retransmisja-pakietow-sack

Odbiorca otrzymał pakiet 1, 2 oraz 4. Pakiet 3 uległ zagubieniu. Odbiorca potwierdza wszystkie pakiety, które otrzymał. W buforze nadawczym, ciągle są dostępne te segmenty, które nie zostały potwierdzone w sposób ciągły, czyli te które nie dotarły w ogóle lub dotarły poza kolejnością. Natomiast odbiorca ma u siebie w buforze, te pakiety, które otrzymał poza kolejnością. Po chwili serwer retransmituje zaginione pakiety. Widzi jednak, że część z nich jest oznaczona bitem SACK i te zostawia w spokoju. Przesłaniu ulegają jedynie te, które nie mają ustawionego tego bitu. Serwer oczyszcza flagę flagę SACK z pakietu znajdującego się w jego buforze. Po chwili zagubiony pakiet trafia już do odbiorcy. Ten zaś wysyła pakiet potwierdzający ciągłość odebranych danych, tj. w punkcie gdzie powinna rozpocząć się transmisja nowych danych i oba bufory zostają opróżnione.

Dzięki takiemu rozwiązaniu możemy znacznie zminimalizować ilość retransmitowanych danych, dlatego też dobrze jest włączyć taką opcję w kernelu linuxa. Możemy to zrobić przez dopisanie do pliku /etc/sysctl.conf tych poniższych linijek:

net.ipv4.tcp_sack = 1
net.ipv4.tcp_dsack = 1
net.ipv4.tcp_fack = 1

W pewnych warunkach jednak, mogą pojawić się też problemy z wydajnością serwera. Atakujący może zmusić maszynę do trzymania sporej kolejki na retransmisje pakietów przez długi czas, co może zjeść procesor, pamięć RAM oraz więcej łącza niż w rzeczywistości powinno. Jeśli serwer jest solidny i nie przesyła dużych plików, tego typu sytuacja mu nie zagraża. W przypadku gdy serwer ma na celu dbanie o jak najniższe opóźnienia, SACK jest zbędny i może stanowić zagrożenie dla bezpieczeństwa maszyny. W przypadku słabych i wolnych łącz, SACK może powodować problemy przez nasycenie łącza pakietami ACK i powinien zostać wyłączony.

Mikhail Morfikov avatar
Mikhail Morfikov
Po ponad 10 latach spędzonych z różnej maści linux'ami (Debian/Ubuntu, OpenWRT, Android) mogę śmiało powiedzieć, że nie ma rzeczy niemożliwych i problemów, których nie da się rozwiązać. Jedną umiejętność, którą ludzki umysł musi posiąść, by wybrnąć nawet z tej najbardziej nieprzyjemniej sytuacji, to zdolność logicznego rozumowania.