Kill switch się włącza: co dzieje się z otwartymi sesjami TCP?
Zablokowany pakiet to nie zamknięte połączenie. Zdecyduj, czy sesja ma przetrwać przerwę, a potem testuj blokadę i odzyskiwanie jako dwie osobne właściwości.
Tunel pada, kill switch się włącza, a pobieranie, które było w trzech czwartych gotowe, albo zastyga, albo od razu zawodzi. Te dwa wyniki wynikają z różnych decyzji egzekwowania, a nie z różnych poziomów ochrony. Porzucony pakiet pozostawia połączenie w oczekiwaniu, natomiast odrzucony pakiet zamyka je i informuje aplikację. Decyzja, które zachowanie wybrać, jest kwestią projektu, a jego testowanie to osobne ćwiczenie.
Porzucenie, odrzucenie i reset to różne rzeczy
Reguła firewalla, która porzuca ruch, wyrzuca pakiet i nic nie odsyła, więc nadawca dalej wysyła według własnych timerów. Reguła, która odrzuca z TCP reset, natychmiast zamyka połączenie i aplikacja widzi błąd. Większość kill switchy porzuca, bo odrzucenie ujawniłoby politykę i bo porzucanie przypomina zachowanie martwej sieci.
Blokowanie to nie to samo co zamykanie gniazda. Aplikacja nadal trzyma deskryptor w stanie ustanowionym, a brakuje tylko pakietów. Dlatego strona może minutami siedzieć na spinnerze, podczas gdy system operacyjny upiera się, że połączenie istnieje. Czytaj udokumentowane egzekwowanie, zamiast wnioskować je z komunikatu aplikacji, ponieważ oba zachowania wyglądają jak padnięta sieć.
Co robi aplikacja, gdy trwa przerwa
TCP ponawia z rosnącymi opóźnieniami, a domyślny budżet ponowień Linuksa wyczerpuje się nie w sekundach, lecz po około kwadransie. Do tego czasu gniazdo nie jest ani użytecznie otwarte, ani zamknięte. Aplikacje z własnymi keepalive'ami lub limitami czasu żądań często poddają się wcześniej, dlatego dwa programy na tej samej maszynie zachowują się różnie podczas jednej awarii.
Gdy tunel wraca, lokalne gniazdo się nie zmienia, ale ścieżka może. Nowy publiczny adres źródłowy tworzy na serwerze inną czwórkę, więc zapora stanowa po drugiej stronie nie pasuje już do sesji. Połączenie jest martwe, choć klient nigdy nie zobaczył błędu.
Zdecyduj, czy odzyskiwanie jest konieczne
Wybierz między dwoma kontraktami. Albo sesja musi przetrwać krótką przerwę, co wymaga stabilnego adresowania i serwera, który zachowuje swój stan, albo aplikacja musi czysto połączyć się ponownie, co wymaga logiki ponowień bezpiecznej do powtórzenia. Wszystko pomiędzy daje najgorszy wynik: klient, który ponownie wysyła to, co serwer już zapisał, albo taki, który zgłasza sukces dla sesji, której nikt nie widzi.
Stabilne adresowanie to część, o której ludzie zapominają, ponieważ ponowne połączenie lądujące na innym publicznym adresie unieważnia stan po stronie serwera, nawet gdy gniazdo klienta wygląda zdrowo. Zapisz, który z dwóch kontraktów dotyczy każdej aplikacji, ponieważ rzadko wszystkie się pokrywają.
Sprawdź blokadę i odzyskiwanie osobno
Traktuj ochronę przed wyciekiem i przetrwanie sesji jako dwie właściwości, ponieważ zdanie jednej nie mówi nic o drugiej. Sesja, która przetrwała, nie jest dowodem, że bezpośredni ruch został zablokowany, a sesja, która zginęła, nie jest dowodem, że zablokowano każdą bezpośrednią trasę.
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'
Podczas obserwacji odzyskiwania używaj nieszkodliwej operacji testowej, aby zduplikowane wysłanie nie stało się incydentem. Zapisz tryb awarii, który naprawdę widziałeś: co pokazała aplikacja, czy gniazdo przetrwało i kiedy samo się podniosło.
Zapisz oczekiwane zachowanie obok reguły egzekwowania i opatrz je datą. Następna osoba, która zmieni tę regułę, musi wiedzieć, który z dwóch kontraktów obiecało wdrożenie.