tcpdump i Wireshark przy pracy przez proxy: diagnoza zerwań
Spis treści
- Wprowadzenie: kiedy logi klienta już nie wystarczają
- Podstawy: trzy segmenty jednego połączenia
- Głębokie zanurzenie: dlaczego w tunelu widać tylko connect
- Tcpdump w praktyce: robimy zrzut bez gigabajtów
- Wireshark: czytanie zrzutu jak otwartej księgi
- Diagnoza po zrzucie: kto dokładnie zerwał połączenie
- Odszyfrowanie własnego ruchu przez sslkeylogfile
- Typowe obrazy zerwań i jak je czytać
- Typowe błędy przy robieniu i czytaniu zrzutu
- Narzędzia i zasoby inżyniera
- Case'y i wyniki zastosowania
- Lista kontrolna robienia zrzutu do zgłoszenia w support
- Faq: częste pytania o zrzuty przez proxy
Logi klienta są cudowne dokładnie do momentu, w którym coś pokazują. Ale pewnego dnia trafiasz w ścianę: aplikacja pisze lakonicznie connection reset, proxy w swoich logach milczy, a serwer docelowy zarzeka się, że u niego wszystko gra. Kto kłamie? Nikt. Po prostu patrzysz na problem z najwyższego piętra, a prawda mieszka na poziomie pakietów. I tam trzeba zejść.
Ten artykuł to szczegółowy przewodnik inżynierski po pracy z tcpdump i Wireshark w tych przypadkach, gdy ruch idzie przez proxy. Przeanalizujemy, co dokładnie widzi obserwator przed proxy i za nim, dlaczego wewnątrz tunelu HTTPS widać tylko żądanie CONNECT i nic więcej, oraz jak po jednym zrzucie odróżnić zerwanie po swojej stronie od zerwania po stronie serwera docelowego. To nie jest o przechwytywaniu i podmianie HTTPS na poziomie aplikacji - to o poziomie pakietów i uczciwej diagnozie zerwań.
Wprowadzenie: kiedy logi klienta już nie wystarczają
Wyobraź sobie typową infrastrukturę. Twoja aplikacja odwołuje się do zewnętrznego API przez proxy HTTP Proxeon. Zwykle wszystko działa. Ale pięć procent żądań kończy się błędem i nie rozumiesz dlaczego. Logi aplikacji pokazują tylko fakt zerwania. Logi proxy pokazują, że tunel został ustanowiony. Serwer docelowy jest poza twoją kontrolą. Utknąłeś między trzema czarnymi skrzynkami.
Właśnie tutaj zaczyna się diagnostyka pakietowa. Zrzut ruchu to stenogram rozmowy między maszynami, zapisany dosłownie, bez interpretacji i bez prawa do kłamstwa. Pakiet albo przyszedł, albo nie. Flaga RST albo jest, albo jej nie ma. TCP nie umie udawać. A jeśli nauczysz się czytać ten stenogram, przestaniesz zgadywać.
Z tego przewodnika dowiesz się: jak zrobić zrzut komendą tcpdump tak, żeby nie zapchać dysku gigabajtami; które filtry wyświetlania w Wireshark oszczędzają godziny; jak odczytać handshake TLS nawet bez odszyfrowania; jak po flagach określić winowajcę zerwania; i jak legalnie odszyfrować własny ruch przez zmienną SSLKEYLOGFILE. Na końcu czeka na ciebie gotowa lista kontrolna do zgłoszenia w support oraz szczegółowe FAQ.
Podstawy: trzy segmenty jednego połączenia
Pierwsza rzecz, którą trzeba sobie przyswoić: gdy klient pracuje przez proxy, to nie jest jedno połączenie, a co najmniej dwa różne połączenia TCP. Jedno - od klienta do proxy. Drugie - od proxy do serwera docelowego. To fundament, bez którego dalsza analiza nie ma sensu.
Czym jest zrzut i jak jest zbudowany
Zrzut pakietów to sekwencja pakietów sieciowych przechwyconych na konkretnym interfejsie sieciowym konkretnej maszyny. Kluczowe słowo - konkretnej. Zawsze widzisz tylko ten ruch, który fizycznie przechodzi przez punkt przechwytywania. Robiąc zrzut na kliencie, widzisz rozmowę klient-proxy. Robiąc go na proxy, widzisz obie strony. Na serwerze docelowym - tylko rozmowę proxy-serwer.
Każdy pakiet niesie nagłówki kolejnych warstw: Ethernet, IP, TCP lub UDP, oraz ładunek. Do diagnozy zerwań interesuje nas przede wszystkim warstwa TCP: numery portów, numery sekwencyjne (sequence), potwierdzenia (ACK) i flagi - SYN, ACK, FIN, RST, PSH.
Model proxy: dwa połączenia zamiast jednego
Przeanalizujmy schemat przepływu ruchu przy pracy z proxy HTTP w trybie tunelu:
- Segment A (klient - proxy). Klient otwiera połączenie TCP do IP i portu proxy. Tym kanałem wysyła komendę ustanowienia tunelu.
- Segment B (proxy - serwer docelowy). Proxy w swoim imieniu otwiera osobne połączenie TCP do serwera docelowego. To już inny src-IP, inny src-port, inny stan.
- Tunel logiczny. Po ustanowieniu proxy zaczyna na ślepo przekładać bajty z segmentu A do segmentu B i odwrotnie. Nie rozbiera tego, co jest w środku.
Dlaczego to ważne dla diagnostyki? Bo zerwanie może nastąpić w każdym z dwóch segmentów, a z punktu widzenia klienta objaw będzie identyczny - połączenie padło. Ale przyczyna, a więc i rozwiązanie, są różne.
Proxy HTTP, SOCKS i tunelowanie
Przy zwykłym żądaniu HTTP bez szyfrowania proxy widzi i metodę, i URL, i nagłówki. Ale gdy tylko mowa o HTTPS, obraz się zmienia. Klient nie może oddać proxy niezaszyfrowanego żądania - inaczej traci sens szyfrowania. Dlatego stosuje się mechanizm tunelowania: klient mówi proxy połącz mnie z tym hostem na tym porcie i dalej się nie wtrącaj. Ta komenda to właśnie CONNECT.
Głębokie zanurzenie: dlaczego w tunelu widać tylko CONNECT
To chyba najczęstsze źródło zdziwienia u inżynierów, którzy pierwszy raz otworzyli zrzut ruchu HTTPS przez proxy. Spodziewasz się zobaczyć żądania i odpowiedzi, a widzisz jedną linijkę i dalej nieczytelną papkę. Zastanówmy się, dlaczego tak jest i dlaczego to jest prawidłowe.
Anatomia CONNECT
Gdy klient chce ustanowić zabezpieczone połączenie przez proxy, wysyła do proxy takie żądanie w otwartym tekście:
CONNECT api.example.com:443 HTTP/1.1\r\nHost: api.example.com:443\r\n\r\nProxy otwiera połączenie TCP do api.example.com na port 443, a jeśli wszystko się udało, odpowiada klientowi:
HTTP/1.1 200 Connection established\r\n\r\nOd tego momentu proxy zamienia się w głupią rurę. Wszystko, co klient wyśle dalej, proxy przekazuje serwerowi bajt w bajt, i odwrotnie. A co klient wysyła dalej? TLS ClientHello, początek handshake'u. Zaszyfrowana wymiana. Proxy nie ma kluczy i fizycznie nie może zajrzeć do środka.
Co to oznacza dla obserwatora ze zrzutem
Jeśli robisz zrzut na kliencie albo na proxy, zobaczysz:
- Ustanowienie połączenia TCP do proxy (SYN, SYN-ACK, ACK).
- Otwarty tekst żądania CONNECT z nazwą hosta docelowego i portem.
- Odpowiedź proxy o statusie ustanowienia tunelu.
- A dalej - tylko rekordy TLS, zaszyfrowany strumień, z którego gołym okiem odczytasz jedynie metadane handshake'u.
Oto główny wniosek: nazwa hosta docelowego jest w zrzucie widoczna zawsze - w linii CONNECT. Nawet bez jednego odszyfrowanego bajtu wiesz, dokąd dokładnie klient próbował trafić. To bezcenne przy diagnozie: od razu odcinasz pytanie a czy żądanie w ogóle tam szło.
TLS SNI: drugie źródło nazwy hosta
Nawet gdyby CONNECT nie było (na przykład przy bezpośrednim połączeniu bez proxy), nazwa hosta jest często widoczna w polu SNI wewnątrz ClientHello. Server Name Indication jest przekazywane w otwartym tekście na początku handshake'u. Wireshark świetnie je pokazuje. We współczesnych sieciach rośnie popularność Encrypted Client Hello, ukrywającego SNI, ale przy pracy przez tunel CONNECT nie przeszkadza to w diagnozie - nazwa hosta została już podana w samym CONNECT.
tcpdump w praktyce: robimy zrzut bez gigabajtów
Przechodzimy do rąk. tcpdump to narzędzie wiersza poleceń do przechwytywania pakietów, dostępne niemal w każdym systemie uniksopodobnym. Jest potężne, lekkie i niezastąpione na serwerach, gdzie nie ma grafiki. Przeanalizujmy kluczowe scenariusze.
Podstawowe przechwytywanie na właściwym interfejsie
Najpierw zobaczmy listę interfejsów:
tcpdump -DPrzechwytywanie na konkretnym interfejsie z wypisem na ekran:
tcpdump -i eth0 -nFlaga -n wyłącza rozwiązywanie nazw, żeby tcpdump nie zwalniał na zapytaniach DNS i pokazywał czyste IP. To ważne: rozwiązywanie nazw w czasie rzeczywistym zniekształca obraz i spowalnia przechwytywanie.
Filtrowanie po hoście i porcie
Przechwytywanie całego ruchu interfejsu na obciążonym serwerze to prosta droga do gigabajtów śmieci. Filtruj od samego początku. Przechwytywanie ruchu do konkretnego proxy po IP i porcie:
tcpdump -i eth0 -n host 203.0.113.10 and port 8080Przechwytywanie tylko do serwera docelowego (przydatne po stronie proxy):
tcpdump -i eth0 -n host api.example.com and port 443Kombinacja: ruch do proxy LUB do serwera docelowego:
tcpdump -i eth0 -n "(host 203.0.113.10 and port 8080) or (host 198.51.100.5 and port 443)"Zwróć uwagę na cudzysłowy: gdy w wyrażeniu są nawiasy i operatory logiczne, obejmij filtr cudzysłowami, żeby powłoka nie zinterpretowała znaków specjalnych.
Zapis do pliku i właściwy format
Do późniejszej analizy w Wireshark potrzebny jest plik w formacie pcap. Flaga -w zapisuje surowe pakiety do pliku:
tcpdump -i eth0 -n host 203.0.113.10 and port 8080 -w dump.pcapBardzo ważna kwestia: -s 0 lub współczesne zachowanie domyślne przechwytuje pakiet w całości (snaplen). Starsze wersje obcinały pakiety. Jeśli potrzebujesz pełnych danych, upewnij się, że snaplen jest wystarczający:
tcpdump -i eth0 -n -s 0 host 203.0.113.10 and port 8080 -w dump.pcapJeśli natomiast potrzebujesz tylko nagłówków do diagnozy zerwań (flagi, seq, ack), a nie zawartości, ogranicz snaplen, żeby plik był bardziej kompaktowy:
tcpdump -i eth0 -n -s 96 host 203.0.113.10 and port 8080 -w headers.pcapRotacja plików: jak nie zapchać dysku
Przy długiej diagnozie problemu występującego sporadycznie przechwytywanie może trwać godzinami. Żeby nie dostać jednego monstrualnego pliku, użyj rotacji po rozmiarze i liczbie plików. Flaga -C określa rozmiar pliku w megabajtach, -W - liczbę plików w buforze cyklicznym:
tcpdump -i eth0 -n host 203.0.113.10 and port 8080 -w dump-%Y%m%d-%H%M%S.pcap -C 100 -W 10Ta komenda utworzy do dziesięciu plików po sto megabajtów. Gdy dziesiąty się zapełni, tcpdump zacznie nadpisywać pierwszy. Tak zawsze przechowujesz ostatni mniej więcej gigabajt ruchu i nigdy nie zapełnisz dysku. Szablon czasu w nazwie pliku czyni archiwum czytelnym.
Alternatywa - rotacja po czasie. Flaga -G określa interwał w sekundach, po którym tworzony jest nowy plik:
tcpdump -i eth0 -n host 203.0.113.10 and port 8080 -G 3600 -w dump-%Y%m%d-%H%M%S.pcapKażda godzina - nowy plik. Wygodne, gdy trzeba potem szybko znaleźć interwał po czasie incydentu.
Przechwytywanie wokół zdarzenia: łapiemy rzadkie zerwanie
Najbardziej zdradliwa sytuacja - problem powtarza się raz na godzinę i nieprzewidywalnie. Uruchamiasz bufor cykliczny i czekasz. Gdy tylko aplikacja zarejestruje błąd, notujesz dokładny czas i zatrzymujesz przechwytywanie. Potem w analizie idziesz do właściwej sekundy. Praktyczny trik: niech aplikacja przy błędzie zapisuje do logu dokładny znacznik czasu z milisekundami - to twoja kotwica w zrzucie.
Filtr po flagach TCP bezpośrednio w tcpdump
Czasem przydaje się przechwycić tylko pakiety z określonymi flagami. Na przykład tylko pakiety z flagą RST, żeby od razu zrozumieć, czy latają resety:
tcpdump -i eth0 -n "tcp[tcpflags] & tcp-rst != 0"Tylko pakiety SYN - wygodne do śledzenia prób ustanowienia połączenia:
tcpdump -i eth0 -n "tcp[tcpflags] & tcp-syn != 0"Kombinacja RST lub FIN do monitorowania zakończeń połączeń do proxy:
tcpdump -i eth0 -n "host 203.0.113.10 and (tcp[tcpflags] & (tcp-rst|tcp-fin) != 0)"Wireshark: czytanie zrzutu jak otwartej księgi
tcpdump łapie, Wireshark czyta. To graficzny analizator z niezwykle bogatym systemem filtrów wyświetlania i dekoderów protokołów. Otwierasz zapisany plik pcap i zaczynasz śledztwo. Przeanalizujmy narzędzia, które naprawdę są potrzebne do naszego zadania.
Filtry wyświetlania kontra filtry przechwytywania
Ważne, żeby ich nie mylić. Filtr przechwytywania (ten w tcpdump) odsiewa pakiety przed zapisem - czego nie złapano, tego nie ma. Filtr wyświetlania w Wireshark to soczewka: jedynie ukrywa zbędne rzeczy z już wczytanego pliku, niczego nie usuwając. Składnia jest inna. Poniżej - filtry właśnie wyświetlania.
Podstawowe filtry wyświetlania
Pokaż tylko ruch do konkretnego IP:
ip.addr == 203.0.113.10Tylko port TCP proxy:
tcp.port == 8080Kombinacja hosta i portu:
ip.addr == 203.0.113.10 && tcp.port == 8080Pokaż tylko pakiety z flagą RST - natychmiast widać wszystkie resety połączeń:
tcp.flags.reset == 1Tylko pakiety z FIN:
tcp.flags.fin == 1Tylko SYN bez ACK - próby otwarcia połączenia:
tcp.flags.syn == 1 && tcp.flags.ack == 0Szukanie CONNECT i nagłówków HTTP
Żeby znaleźć w zrzucie samo żądanie CONNECT:
http.request.method == "CONNECT"Odpowiedź proxy o ustanowieniu tunelu jest widoczna jako odpowiedź HTTP. Odfiltruj wszystkie żądania HTTP:
http.requestWszystkie odpowiedzi HTTP z kodami:
http.responseFollow TCP Stream: składamy rozmowę w całość
To chyba najcenniejsza funkcja Wireshark dla naszego zadania. Prawy klik na dowolnym pakiecie połączenia, potem Follow, potem TCP Stream. Wireshark zbierze całą dwustronną wymianę w jedno okno, gdzie dane klienta i serwera pokazane są w różnych kolorach. Dla niezaszyfrowanego ruchu zobaczysz czysty tekst: żądanie CONNECT, odpowiedź proxy, a dalej nieczytelne bajty TLS.
Właśnie w Follow Stream naocznie widać zerwanie na CONNECT. Pierwsze linie czytają się jak ludzki tekst, potem zaczyna się zaszyfrowany obszar. To potwierdza: tunel ustanowiony, dalej idzie szyfrowanie, i bez kluczy głębiej nie zajrzysz - co jest absolutnie normalne.
Czytanie handshake'u TLS bez odszyfrowania
Nawet bez kluczy handshake TLS mówi wiele. Odfiltruj rekordy uścisku dłoni:
tls.handshakeZnajdź ClientHello, gdzie klient przedstawia się serwerowi:
tls.handshake.type == 1Znajdź ServerHello, odpowiedź serwera:
tls.handshake.type == 2Co daje ta para? Jeśli widzisz ClientHello, ale nigdy nie widzisz ServerHello - serwer nie odpowiedział na handshake. Przyczyna: albo serwer docelowy jest niedostępny za proxy, albo zerwanie nastąpiło przed odpowiedzią. Jeśli widzisz oba, ale potem zerwanie - problem jest głębiej, już w zabezpieczonej wymianie lub na poziomie aplikacji.
Wewnątrz ClientHello bez żadnego odszyfrowania czyta się pole SNI - nazwę hosta, do którego idzie odwołanie:
tls.handshake.extensions_server_name == "api.example.com"Widzisz też proponowane wersje TLS i zestawy szyfrów. Jeśli serwer odpowiada Alertem zamiast ServerHello, znaczy to, że handshake został odrzucony - na przykład niezgodność wersji lub szyfrów. Filtr dla alertów:
tls.alert_messageDiagnoza po zrzucie: kto dokładnie zerwał połączenie
Dotarliśmy do serca artykułu. Połączenie padło - pytanie brzmi, kto je zerwał i dlaczego. TCP zostawia dowody, po których można wydać werdykt. Przeanalizujmy kluczowe sygnały.
Normalne zakończenie: FIN
Standardowe zamknięcie połączenia następuje przez wymianę pakietów FIN. Jedna strona mówi skończyłem transmisję, druga potwierdza i też wysyła FIN. To uprzejme pożegnanie. Jeśli w zrzucie widzisz schludną wymianę FIN-ACK-FIN-ACK, połączenie zamknęło się prawidłowo. Pytanie tylko, czy twój klient oczekiwał tego zamknięcia. Jeśli serwer wysłał FIN, oddawszy odpowiedź w całości, wszystko dobrze. Jeśli FIN przyszedł w środku oczekiwanych danych - serwer zamknął przed czasem.
Awaryjne zakończenie: RST
Flaga RST to brutalne zerwanie. Nie pożegnanie, a trzaśnięcie drzwiami. RST oznacza: to połączenie jest nieważne, natychmiast o nim zapomnij. Przyczyny bywają różne:
- Port zamknięty - nikt nie nasłuchuje po drugiej stronie. RST przychodzi niemal natychmiast po SYN.
- Aplikacja po drugiej stronie awaryjnie zamknęła gniazdo.
- Urządzenie pośredniczące (firewall, load balancer, samo proxy) siłowo zresetowało połączenie po timeoutcie lub zgodnie z polityką.
- Jedna ze stron dostała pakiet dla połączenia, o którym już zapomniała.
Klucz do zagadki - kto wysłał RST. Patrz na source IP pakietu z RST. Jeśli RST przyszedł z IP proxy - zerwało proxy lub coś między proxy a tobą. Jeśli z IP serwera docelowego - znaczy to, że segment proxy-serwer dotarł do serwera, i zerwał już on lub urządzenie obok niego.
Ale pamiętaj o dwóch segmentach. Robiąc zrzut na kliencie, widzisz RST tylko z IP proxy, bo bezpośrednio z serwerem nie rozmawiasz - między wami jest proxy. Żeby zrozumieć, co dzieje się w segmencie B, potrzebny jest zrzut po stronie proxy. O tym porozmawiamy w rozdziale o liście kontrolnej.
Ponowne transmisje: retransmission
Wireshark automatycznie oznacza ponowne transmisje. Filtr:
tcp.analysis.retransmissionPonowna transmisja oznacza, że nadawca nie dostał ACK na wysłany segment w terminie i wysyła go ponownie. Pojedyncze retransmisje to norma w internecie. Ale lawina retransmisji to objaw utraty pakietów na trasie. Szczególnie charakterystyczne dla sieci mobilnych i niestabilnych.
Powiązane przydatne filtry. Zduplikowane ACK, sygnalizujące pominięty segment:
tcp.analysis.duplicate_ackWszystkie problematyczne zdarzenia, które Wireshark zdołał rozpoznać:
tcp.analysis.flagsJeśli widzisz serię retransmisji, po której następuje RST, obraz się układa: pakiety ginęły, jedna ze stron zmęczyła się czekaniem i zerwała połączenie. To typowa historia dla słabego kanału.
Zero Window: odbiorca się zadławił
TCP ma mechanizm kontroli przepływu przez okno odbioru. Jeśli odbiorca nie nadąża z przetwarzaniem danych, ogłasza zero window - bufor pełny, przyhamuj. Filtr:
tcp.analysis.zero_windowZero window to nie utrata sieciowa, a sygnał, że aplikacja odbierająca wolno czyta z gniazda. Na przykład twój klient dostaje dużą odpowiedź, ale przetwarza ją w jednym wątku i nie nadąża. Nadawca czeka, okno się nie otwiera, i w końcu może zadziałać timeout. Jeśli po zero window idzie window update, wszystko się znormalizowało. Jeśli po zero window cisza, a potem RST - odbiorca zawiesił się lub padł.
Powiązany sygnał - window full, gdy nadawca utknął w zadeklarowanym oknie i nie może wysyłać dalej:
tcp.analysis.window_fullMacierz werdyktów
Zbierzmy logikę w praktyczny framework. Patrz na ostatnie pakiety żywego połączenia przed zerwaniem:
- SYN jest, SYN-ACK nie ma, potem RST lub cisza. Połączenie się nie ustanowiło. Punkt docelowy niedostępny lub port zamknięty. Przy pracy przez proxy RST przyjdzie od proxy, jeśli niedostępny jest serwer za nim.
- Ustanowienie przeszło, CONNECT wysłany, odpowiedzi nie ma. Proxy przyjęło komendę, ale nie zdołało dotrzeć do serwera docelowego albo ten milczy. Czekaj na timeout.
- ClientHello jest, ServerHello nie ma. Serwer docelowy nie odpowiedział na handshake. Problem w segmencie proxy-serwer.
- Dane szły, potem RST od serwera. Serwer awaryjnie zamknął połączenie - przeciążenie, błąd aplikacji, timeout po jego stronie.
- Dane szły, potem FIN od serwera w środku odpowiedzi. Serwer zamknął prawidłowo, ale wcześniej, niż klient oczekiwał - prawdopodobnie limit rozmiaru odpowiedzi lub timeout żądania.
- Lawina retransmission, potem RST. Utraty w kanale. Szukaj problemu w sieci - połączenie mobilne, przeciążona trasa.
- Zero window, potem cisza. Twój klient nie czytał danych wystarczająco szybko. Problem po twojej stronie w przetwarzaniu.
Odszyfrowanie własnego ruchu przez SSLKEYLOGFILE
Czasem samych metadanych nie wystarcza - trzeba zobaczyć zawartość zaszyfrowanej wymiany. To legalne i właściwe tylko wtedy, gdy ruch jest twój własny: twój klient, twoje klucze, twoja aplikacja. Nie przechwytujemy cudzego i nie podmieniamy certyfikatów. Prosimy naszego własnego klienta, żeby uprzejmie zapisał klucze sesyjne do pliku, by potem podać je Wireshark.
Jak to działa
Wiele bibliotek klienckich TLS obsługuje zmienną środowiskową SSLKEYLOGFILE. Jeśli jest ustawiona, biblioteka dopisuje do wskazanego pliku sekrety sesji w standardowym formacie. Wireshark umie czytać ten plik i odszyfrowywać odpowiadające sesje w zrzucie. Żadnej magii i żadnego hakowania - klient sam dobrowolnie oddaje swoje klucze, bo ty, właściciel klienta, tak zarządziłeś.
Przykład dla wiersza poleceń i przeglądarek na silniku z obsługą
Ustawienie zmiennej przed uruchomieniem aplikacji w systemie uniksopodobnym:
export SSLKEYLOGFILE=/home/user/tls-keys.logUruchomienie klienta, na przykład curl, obsługującego tę zmienną przy kompilacji z odpowiednią biblioteką:
SSLKEYLOGFILE=/home/user/tls-keys.log curl -x http://203.0.113.10:8080 https://api.example.com/statusTutaj flaga -x ustawia proxy Proxeon, a SSLKEYLOGFILE wymusza zapis kluczy sesji. Równolegle robisz zrzut przez tcpdump. Potem masz i pcap, i plik kluczy.
Podłączanie kluczy w Wireshark
W Wireshark otwórz ustawienia, znajdź sekcję protokołu TLS, podaj ścieżkę do pliku kluczy w polu dla pliku logu pre-master secret. Potem ponownie wczytaj zrzut. Wcześniej nieczytelne rekordy TLS staną się odszyfrowane: zobaczysz prawdziwe żądania i odpowiedzi HTTP wewnątrz tunelu. Teraz Follow TLS Stream pokaże całą wymianę aplikacyjną.
Ważne granice stosowalności
- Odszyfrowywany jest tylko ten ruch, którego klucze trafiły do pliku. Cudze sesje pozostają zaszyfrowane - i to jest prawidłowe.
- Klucze są wrażliwe. Plik tls-keys.log faktycznie otwiera zawartość twoich sesji. Trzymaj go jak sekret, usuwaj po debugowaniu.
- Metoda jest przeznaczona do debugowania własnych aplikacji, a nie do obserwacji cudzego ruchu. To zasadnicza granica etyczna i prawna.
Typowe obrazy zerwań i jak je czytać
Teoria bez rozpoznawalnych wzorców szybko wietrzeje. Przeanalizujmy kilka charakterystycznych scenariuszy, które będziesz spotykać raz za razem. Naucz się rozpoznawać je od pierwszego spojrzenia.
Timeout połączenia: serwer za proxy niedostępny
Obraz w zrzucie na kliencie: TCP do proxy ustanowiło się prawidłowo, klient wysłał CONNECT i nastała cisza. Odpowiedzi 200 od proxy nie ma. Po jakimś czasie albo przychodzi RST od proxy, albo aplikacja sama zamyka połączenie po swoim timeoutcie.
Co to znaczy: proxy przyjęło twoją komendę, próbowało otworzyć segment B do serwera docelowego, ale ten nie odpowiedział. Serwer docelowy leży, port zamknięty, lub trasa do niego zerwana. Twoja strona i proxy działają prawidłowo. Działanie: sprawdzić dostępność hosta docelowego, w razie potrzeby zrobić zrzut po stronie proxy, żeby zobaczyć segment B.
Zerwanie w środku odpowiedzi
Obraz: tunel ustanowiony, TLS zadziałał, poszły dane, część odpowiedzi odebrana, i nagle FIN lub RST od strony serwera. Klient dostał niepełną odpowiedź i narzeka na ucięty content.
Jeśli to FIN, serwer zamknął prawidłowo, ale przedwcześnie - być może zadziałał limit czasu generowania odpowiedzi lub ograniczenie rozmiaru po jego stronie. Jeśli to RST, serwer lub urządzenie obok niego zerwały awaryjnie. Działanie: jeśli problem powtarza się przy dużych odpowiedziach - szukaj timeoutów i limitów. Odszyfrowanie własnego ruchu przez SSLKEYLOGFILE pomoże zobaczyć, czy odebrano nagłówek HTTP i ile ciała zdołało przyjść.
Utraty w sieci mobilnej
Obraz: mnóstwo pakietów oznaczonych jako retransmission, pojawiają się duplicate ack, obserwuje się wyraźne skoki czasu między pakietami. Połączenie albo boleśnie wolne, albo w końcu rwie się po timeoutcie.
To klasyka niestabilnego kanału radiowego. Pakiety giną, TCP je przesyła ponownie, prędkość spada. Sieci mobilne mają też skłonność do zrywania długo bezczynnych połączeń przez timeouts NAT urządzeń pośredniczących operatora: w środku ciszy nagle przylatuje RST, gdy jedna ze stron próbuje wznowić wymianę na połączeniu, o którym operator już zapomniał. Działanie: ustawić rozsądne keep-alive i timeouts, ponowne próby na poziomie aplikacji, nie trzymać długich bezczynnych połączeń.
Proxy w ogóle niedostępne
Obraz: klient wysyła SYN na IP i port proxy, ale nie dostaje SYN-ACK. Albo cisza i retransmisje SYN, albo natychmiastowy RST. Jeśli cisza - między tobą a proxy coś filtruje pakiety albo proxy nie nasłuchuje. Jeśli natychmiastowy RST - na tym porcie nikt nie odpowiada. Działanie: sprawdzić adres i port proxy, dostępność sieciową, poprawność konfiguracji.
Wolny klient: zero window
Obraz: wymiana idzie, ale okresowo klient ogłasza zero window, nadawca się wstrzymuje, potem window update wznawia strumień. Jeśli powtarza się to często, twoja aplikacja czyta z gniazda wolniej, niż serwer oddaje. Działanie: zoptymalizować przetwarzanie odpowiedzi, czytać strumień w osobnym wątku, zwiększyć bufory.
Typowe błędy przy robieniu i czytaniu zrzutu
Doświadczenie to zbiór nabitych guzów. Zbierzmy najczęstsze błędy, żebyś ich nie powtarzał.
- Robić zrzut nie tam. Szukasz zerwania w segmencie proxy-serwer, a zrzut zrobiłeś na kliencie, gdzie tego segmentu w ogóle nie widać. Zawsze myśl, którego segmentu potrzebujesz, i rób zrzut w właściwym punkcie.
- Przechwytywać wszystko pod rząd. Bez filtra na obciążonym serwerze dostaniesz gigabajty i utoniesz w nich. Filtruj po hoście i porcie od samego początku.
- Ucięty snaplen tam, gdzie potrzebne są dane. Jeśli chcesz widzieć zawartość, a ustawiłeś krótki snaplen, ładunek zostanie ucięty, a Follow Stream pokaże strzępy.
- Rozwiązywanie nazw włączone. Zapomniałeś flagi -n, i tcpdump zwalnia na DNS, zniekształcając czasy. Zawsze -n przy przechwytywaniu.
- Ignorować kierunek RST. Widzą RST i wyciągają wniosek, nie patrząc, kto go wysłał. Source IP pakietu RST to połowa odpowiedzi.
- Mylić prawidłowy FIN z awarią. FIN to normalne zamknięcie. Panikować trzeba nie od samego FIN, a od FIN, który przyszedł przed oczekiwanym końcem danych.
- Zapominać o strefach czasowych i dokładnym czasie. Logi aplikacji i zrzut muszą być zsynchronizowane czasowo, inaczej nie znajdziesz właściwego momentu. Trzymaj NTP w porządku.
- Przechowywać plik kluczy SSLKEYLOGFILE. Po debugowaniu powinien być usunięty. To sekret ujawniający zawartość twoich sesji.
- Wyciągać wnioski z jednego połączenia. Problemy występujące sporadycznie wymagają statystyki. Jedno padnięte żądanie może być przypadkiem, wzorzec z dziesiątki - diagnozą.
Narzędzia i zasoby inżyniera
Zbierzmy arsenał, który warto mieć pod ręką przy pracy z ruchem proxy.
Przechwytywanie
- tcpdump - podstawowe narzędzie przechwytywania na serwerach i w konsoli. Lekkie, zawsze dostępne, elastyczny filtr.
- dumpcap - konsolowe narzędzie z zestawu Wireshark, specjalnie nastawione na wydajne przechwytywanie z rotacją.
- tshark - konsolowy Wireshark. Pozwala stosować filtry wyświetlania bez grafiki, wygodny dla skryptów i zdalnych serwerów.
Analiza
- Wireshark - graficzny analizator, dekodery setek protokołów, potężny system filtrów, Follow Stream, statystyki połączeń.
- Informacja ekspercka Wireshark - wbudowany panel podświetlający anomalie: retransmisje, resety, zero window. Zaczynaj śledztwo właśnie od niego.
- Statystyki konwersacji - tabela wszystkich połączeń TCP w zrzucie z bajtami i czasem trwania. Szybko widać, które połączenie jest anormalnie krótkie.
Przydatne triki wiersza poleceń
Szybko zobaczyć zawartość pcap w konsoli przez tshark z filtrem wyświetlania:
tshark -r dump.pcap -Y "tcp.flags.reset == 1"Wypisać tylko żądania CONNECT z pliku:
tshark -r dump.pcap -Y "http.request.method == \"CONNECT\""Zobaczyć wszystkie retransmisje:
tshark -r dump.pcap -Y "tcp.analysis.retransmission"Te komendy są bezcenne, gdy nie ma grafiki, a trzeba się rozeznać tu i teraz, przez ssh.
Case'y i wyniki zastosowania
Nic nie przekonuje lepiej niż żywe historie. Podam zbiorcze case'y odzwierciedlające realną praktykę inżynierską przy diagnozie ruchu proxy.
Case 1: pięć procent żądań pada w nocy
Zespół integracji skarżył się: około pięciu procent żądań do zewnętrznego API przez proxy padało z uciętą odpowiedzią, głównie w nocy. Logi aplikacji pokazywały niepełny content. Logi proxy - ustanowione tunele bez błędów.
Zrębili zrzut na kliencie z rotacją cykliczną na kilka godzin i dokładnym znacznikiem błędu z logu. W momencie incydentu zobaczyli: tunel ustanowiony, TLS zadziałał, część ciała odpowiedzi przyszła, potem FIN od proxy. Odszyfrowanie własnego ruchu przez SSLKEYLOGFILE pokazało: przychodził poprawny nagłówek HTTP ze wskazaniem rozmiaru ciała, ale ciało rwało się w połowie. Wniosek: serwer docelowy zamykał połączenie po swoim timeoutcie generowania dużych nocnych raportów. Rozwiązanie po stronie integracji - pobierać dane stronicowo, mniejszymi porcjami. Problem zniknął całkowicie.
Case 2: tajemniczy natychmiastowy RST
Inny inżynier dostawał natychmiastowy reset zaraz po wysłaniu CONNECT dla jednego konkretnego hosta, podczas gdy dla innych hostów wszystko działało. Pierwsze podejrzenie padło na proxy.
Zrzut na kliencie pokazał: CONNECT poszedł, i niemal natychmiast wrócił RST z IP proxy. Ale ta natychmiastowość niepokoiła - zwykle niedostępność serwera daje timeout, a nie natychmiastowy reset. Zrobili zrzut po stronie proxy i zobaczyli segment B: proxy otwierało połączenie do hosta docelowego na właściwy port, a serwer docelowy odpowiadał RST na SYN - port był zamknięty. Proxy uczciwie transmitowało tę odmowę klientowi. Okazało się, że usługa docelowa niedawno zmieniła port. Wniosek: natychmiastowy RST to najczęściej zamknięty port, a nie problem proxy. Właściwy port przywrócił działanie.
Case 3: degradacja w segmencie mobilnym
Aplikacja na urządzeniach mobilnych, pracująca przez proxy, u części użytkowników regularnie traciła połączenie. Zrzut z urządzenia w problematycznej strefie zasięgu pokazał klasyczny obraz: serie retransmisji, zduplikowane ACK, rosnące interwały, i w finale RST po długiej bezczynności - wynik NAT timeoutu u operatora.
Wniosek: sieć, nie proxy i nie serwer. Rozwiązanie - na poziomie aplikacji wprowadzono adaptacyjne ponowne próby, rozsądne keep-alive i wdzięczne obsługiwanie zerwań z ponownym ustanawianiem połączenia. Liczba błędów widocznych dla użytkownika spadła wielokrotnie, choć sam kanał radiowy pozostał ten sam. Zrzut pakietów pozwolił nie tracić czasu na fałszywe hipotezy o proxy i skupić się na rzeczywistej przyczynie.
Wspólny wniosek z case'ów
We wszystkich trzech historiach zrzut oszczędził tygodnie korespondencji i wzajemnych oskarżeń między zespołami. Pakiety nie kłamią. Gdy tylko na stole pojawia się zrzut z kierunkiem RST, obecnością lub brakiem ServerHello i obrazem retransmisji, spór o winowajcę kończy się w kilka minut. To właśnie główna wartość tej metody: przenosi diagnozę z płaszczyzny opinii do płaszczyzny faktów.
Lista kontrolna robienia zrzutu do zgłoszenia w support
Gdy zwracasz się do supportu - czy dostawcy proxy Proxeon, czy właściciela docelowego API - umiejętnie zrobiony zrzut przyspiesza rozwiązanie wielokrotnie. Oto lista kontrolna, którą warto wykonać przed zgłoszeniem.
Przed przechwytywaniem
- Zanotuj dokładny czas rozpoczęcia diagnozy i zsynchronizuj zegary przez NTP na wszystkich uczestniczących maszynach.
- Określ punkty przechwytywania: co najmniej na kliencie, w miarę możliwości - i po stronie, do której masz dostęp.
- Zbierz dane wstępne: IP i port proxy, nazwę i port hosta docelowego, oczekiwane i faktyczne zachowanie.
Podczas przechwytywania
- Uruchom tcpdump z filtrem po hoście proxy i porcie docelowym, z pełnym snaplenem i rotacją:
tcpdump -i eth0 -n -s 0 "host 203.0.113.10 and port 8080" -w support-%Y%m%d-%H%M%S.pcap -C 100 -W 10 - Odtwórz problem i zapisz dokładny czas incydentu z milisekundami z logu aplikacji.
- Nie zapomnij równolegle zachować logów aplikacji za ten sam interwał.
Co załączyć do zgłoszenia
- Sam plik pcap, przycięty do istotnego interwału czasu, żeby nie wysyłać gigabajtów.
- Dokładne znaczniki czasu incydentu i strefę czasową.
- IP i port proxy, nazwę i port hosta docelowego, opis scenariusza.
- Fragment logów aplikacji z błędem.
- Twoją wstępną analizę: kto wysłał RST lub FIN, czy było ServerHello, czy obserwowano retransmisje. To pokazuje, że odrobiłeś pracę domową.
Jak przyciąć pcap do właściwego interwału
Ogromny plik można przyciąć po czasie przez tshark lub editcap. Przykład wycięcia po numerze pakietów lub po filtrze:
tshark -r big.pcap -Y "frame.time >= \"2026-01-01 03:00:00\" && frame.time <= \"2026-01-01 03:05:00\"" -w small.pcapTaki schludny, skupiony zrzut support przetworzy szybko, bo nie będzie musiał szukać igły w stogu siana.
FAQ: częste pytania o zrzuty przez proxy
Dlaczego w zrzucie ruchu HTTPS przez proxy widzę tylko CONNECT i dalej coś nieczytelnego?
Ponieważ po ustanowieniu tunelu proxy jedynie przekazuje zaszyfrowane bajty TLS, nie mając do nich kluczy. Otwartym tekstem idzie tylko komenda CONNECT z nazwą hosta i odpowiedź proxy o ustanowieniu. Wszystko inne jest chronione szyfrowaniem - i dokładnie po to istnieje HTTPS. Żeby zobaczyć zawartość własnego ruchu, użyj SSLKEYLOGFILE.
Jak zrozumieć, że połączenie zerwał właśnie serwer docelowy, a nie proxy?
Patrz na source IP pakietu z RST lub FIN. Ale pamiętaj o dwóch segmentach: na zrzucie z klienta widzisz tylko IP proxy, bo bezpośrednio z serwerem nie rozmawiasz. Żeby precyzyjnie przypisać zerwanie serwerowi docelowemu, potrzebny jest zrzut po stronie proxy, gdzie widoczny jest segment proxy-serwer. Jeśli RST w segmencie B przychodzi z IP serwera - zerwał on.
Czym retransmission różni się od RST pod względem sensu diagnostycznego?
Retransmission to ponowne wysłanie niepotwierdzonego segmentu, oznaka utraty pakietów w kanale, ale połączenie jeszcze żyje i walczy. RST to zakończenie, rozkaz zapomnienia o połączeniu. Lawina retransmisji przechodząca w RST czyta się tak: kanał gubił pakiety, strona zmęczyła się czekaniem i zerwała. Pojedyncze retransmisje to norma internetu.
Co oznacza zero window i czy winne jest w nim proxy?
Zero window ogłasza odbiorca, którego bufor odbioru się przepełnił, ponieważ aplikacja wol