tcpdump и Wireshark при работе через прокси: диагностика обрывов
Содержание статьи
- Введение: когда логов клиента уже не хватает
- Основы: три сегмента одного соединения
- Глубокое погружение: почему в туннеле виден только connect
- Tcpdump на практике: снимаем дамп без гигабайтов
- Wireshark: чтение дампа как открытой книги
- Диагностика по дампу: кто именно оборвал соединение
- Расшифровка своего трафика через sslkeylogfile
- Типичные картины обрывов и как их читать
- Типичные ошибки при снятии и чтении дампа
- Инструменты и ресурсы инженера
- Кейсы и результаты применения
- Чеклист снятия дампа для обращения в поддержку
- Faq: частые вопросы по дампам через прокси
Логи клиента прекрасны ровно до того момента, пока они что-то показывают. Но однажды вы упираетесь в стену: приложение пишет лаконичное connection reset, прокси в своих логах молчит, а целевой сервер клянется, что у него все хорошо. Кто врет? Никто. Просто вы смотрите на проблему с верхнего этажа, а истина живет на уровне пакетов. И туда нужно спуститься.
Эта статья - подробное инженерное руководство по работе с tcpdump и Wireshark в тех случаях, когда трафик идет через прокси. Мы разберем, что именно видно наблюдателю до прокси и после него, почему внутри HTTPS-туннеля виден только запрос CONNECT и ничего больше, и как по одному дампу отличить обрыв на своей стороне от обрыва у целевого сервера. Это не про перехват и подмену HTTPS на уровне приложения - это про пакетный уровень и честную диагностику обрывов.
Введение: когда логов клиента уже не хватает
Представьте типичную инфраструктуру. Ваше приложение обращается к внешнему API через HTTP-прокси Proxeon. Обычно все работает. Но пять процентов запросов падают с ошибкой, и вы не понимаете почему. Логи приложения показывают только факт разрыва. Логи прокси показывают, что туннель был установлен. Целевой сервер вне вашего контроля. Вы застряли между тремя черными ящиками.
Именно здесь начинается пакетная диагностика. Дамп трафика - это стенограмма разговора между машинами, записанная дословно, без интерпретаций и без права на ложь. Пакет либо пришел, либо нет. Флаг RST либо стоит, либо не стоит. TCP не умеет притворяться. И если вы научитесь читать эту стенограмму, вы перестанете гадать.
Из этого руководства вы узнаете: как снять дамп командой tcpdump так, чтобы не залить диск гигабайтами; какие фильтры отображения в Wireshark экономят часы; как прочитать TLS-хендшейк даже без расшифровки; как по флагам определить виновника разрыва; и как легально расшифровать собственный трафик через переменную SSLKEYLOGFILE. В конце вас ждет готовый чеклист для обращения в поддержку и подробный FAQ.
Основы: три сегмента одного соединения
Первое, что нужно уложить в голову: когда клиент работает через прокси, это не одно соединение, а как минимум два разных TCP-соединения. Одно - от клиента к прокси. Другое - от прокси к целевому серверу. Это фундамент, без которого дальнейший разбор бессмысленен.
Что такое дамп и как он устроен
Пакетный дамп - это последовательность сетевых пакетов, захваченных на конкретном сетевом интерфейсе конкретной машины. Ключевое слово - конкретной. Вы всегда видите только тот трафик, который физически проходит через точку захвата. Снимая дамп на клиенте, вы видите разговор клиент-прокси. Снимая на прокси, видите обе стороны. На целевом сервере - только разговор прокси-сервер.
Каждый пакет несет заголовки уровней: Ethernet, IP, TCP или UDP, и полезную нагрузку. Для диагностики обрывов нас в первую очередь интересует TCP-уровень: номера портов, порядковые номера (sequence), подтверждения (ACK) и флаги - SYN, ACK, FIN, RST, PSH.
Модель прокси: два соединения вместо одного
Разберем схему движения трафика при работе с HTTP-прокси в режиме туннеля:
- Сегмент А (клиент - прокси). Клиент открывает TCP-соединение к IP и порту прокси. По этому каналу он отправляет команду установить туннель.
- Сегмент Б (прокси - целевой сервер). Прокси от своего имени открыв��ет отдельное TCP-соединение к целевому серверу. Это уже другой src-IP, другой src-порт, другое состояние.
- Логический туннель. После установки прокси начинает слепо перекладывать байты из сегмента А в сегмент Б и обратно. Он не разбирает, что внутри.
Почему это важно для диагностики? Потому что обрыв может произойти на любом из двух сегментов, и с точки зрения клиента симптом будет одинаковым - соединение упало. Но причина, а значит и решение, разные.
HTTP-прокси, SOCKS и туннелирование
При обычном HTTP-запросе без шифрования прокси видит и метод, и URL, и заголовки. Но как только речь идет об HTTPS, картина меняется. Клиент не может отдать прокси незашифрованный запрос - иначе теряется смысл шифрования. Поэтому применяется механизм туннелирования: клиент говорит прокси соедини меня вот с этим хостом на этом порту и дальше не вмешивайся. Эта команда и есть CONNECT.
Глубокое погружение: почему в туннеле виден только CONNECT
Это, пожалуй, самый частый источник недоумения у инженеров, впервые открывших дамп HTTPS-трафика через прокси. Ожидаешь увидеть запросы и ответы, а видишь одну строчку и дальше нечитаемую кашу. Давайте разберемся, почему так, и почему это правильно.
Анатомия CONNECT
Когда клиент хочет установить защищенное соединение через прокси, он отправляет прокси такой запрос в открытом виде:
CONNECT api.example.com:443 HTTP/1.1\r\nHost: api.example.com:443\r\n\r\nПрокси открывает TCP-соединение к api.example.com на порт 443, и если все удалось, отвечает клиенту:
HTTP/1.1 200 Connection established\r\n\r\nС этого момента прокси превращается в тупую трубу. Все, что клиент отправит дальше, прокси перешлет серверу байт в байт, и наоборот. А что клиент отправляет дальше? TLS ClientHello, начало рукопожатия. Зашифрованный обмен. Прокси не имеет ключей и физически не может заглянуть внутрь.
Что это значит для наблюдателя с дампом
Если вы снимаете дамп на клиенте или на прокси, вы увидите:
- Установку TCP-соединения к прокси (SYN, SYN-ACK, ACK).
- Открытый текст запроса CONNECT с именем целевого хоста и портом.
- Ответ прокси о статусе установки туннеля.
- А дальше - только TLS-записи, зашифрованный поток, из которого невооруженным глазом читаются лишь метаданные хендшейка.
Вот главный инсайт: имя целевого хоста в дампе видно всегда - в строке CONNECT. Даже без единого расшифрованного байта вы знаете, куда именно клиент пытался попасть. Это бесценно при диагностике: сразу отсекаете вопрос а туда ли вообще шел запрос.
TLS SNI: второй источник имени хоста
Даже если бы CONNECT не было (например, при прямом соединении без прокси), имя хоста часто видно в поле SNI внутри ClientHello. Server Name Indication передается в открытом виде в начале рукопожатия. Wireshark прекрасно его показывает. В современных сетях набирает популярность Encrypted Client Hello, скрывающий SNI, но при работе через CONNECT-туннель это не мешает диагностике - имя хоста уже названо в самом CONNECT.
tcpdump на практике: снимаем дамп без гигабайтов
Переходим к рукам. tcpdump - это утилита командной строки для захвата пакетов, доступная почти в любой Unix-подобной системе. Она мощная, легкая и незаменимая на серверах, где нет графики. Разберем ключевые сценарии.
Базовый захват на нужном интерфейсе
Сначала посмотрим список интерфейсов:
tcpdump -DЗахват на конкретном интерфейсе с выводом на экран:
tcpdump -i eth0 -nФлаг -n отключает разрешение имен, чтобы tcpdump не тормозил на DNS-запросах и показывал чистые IP. Это важно: резолвинг в реальном времени искажает картину и замедляет захват.
Фильтрация по хосту и порту
Снимать весь трафик интерфейса на нагруженном сервере - верный путь к гигабайтам мусора. Фильтруйте с самого начала. Захват трафика к конкретному прокси по IP и порту:
tcpdump -i eth0 -n host 203.0.113.10 and port 8080Захват только к целевому серверу (полезно на стороне прокси):
tcpdump -i eth0 -n host api.example.com and port 443Комбинирование: трафик к прокси ИЛИ к целевому серверу:
tcpdump -i eth0 -n "(host 203.0.113.10 and port 8080) or (host 198.51.100.5 and port 443)"Обратите внимание на кавычки: когда в выражении есть скобки и логические операторы, оборачивайте фильтр в кавычки, чтобы оболочка не интерпретировала спецсимволы.
Запись в файл и правильный формат
Для последующего анализа в Wireshark нужен файл в формате pcap. Флаг -w пишет сырые пакеты в файл:
tcpdump -i eth0 -n host 203.0.113.10 and port 8080 -w dump.pcapКрайне важный момент: -s 0 или современное поведение по умолчанию захватывает пакет целиком (snaplen). Старые версии обрезали пакеты. Если вам нужны полные данные, убедитесь, что snaplen достаточен:
tcpdump -i eth0 -n -s 0 host 203.0.113.10 and port 8080 -w dump.pcapЕсли же вам нужны только заголовки для диагностики обрывов (флаги, seq, ack), а не содержимое, ограничьте snaplen, чтобы файл был компактнее:
tcpdump -i eth0 -n -s 96 host 203.0.113.10 and port 8080 -w headers.pcapРотация файлов: как не залить диск
При долгой диагностике интермиттирующей проблемы захват может идти часами. Чтобы не получить один монструозный файл, используйте ротацию по размеру и количеству файлов. Флаг -C задает размер файла в мегабайтах, -W - количество файлов в кольцевом буфере:
tcpdump -i eth0 -n host 203.0.113.10 and port 8080 -w dump-%Y%m%d-%H%M%S.pcap -C 100 -W 10Эта команда создаст до десяти файлов по сто мегабайт. Когда десятый заполнится, tcpdump начнет перезаписывать первый. Так вы всегда храните последний примерно гигабайт трафика и никогда не переполните диск. Шаблон времени в имени файла делает архив читаемым.
Альтернатива - ротация по времени. Флаг -G задает интервал в секундах, после которого создается новый файл:
tcpdump -i eth0 -n host 203.0.113.10 and port 8080 -G 3600 -w dump-%Y%m%d-%H%M%S.pcapКаждый час - новый файл. Удобно, когда нужно потом быстро найти интервал по времени инцидента.
Захват вокруг события: ловим редкий обрыв
Самая коварная ситуация - проблема воспроизводится раз в час и непредсказуемо. Запускаете кольцевой буфер и ждете. Как только приложение зафиксировало ошибку, отмечаете точное время и останавливаете захват. Затем в анализе идете к нужной секунде. Практический трюк: пусть приложение при ошибке пишет в лог точную временную метку с миллисекундами - это ваш якорь в дампе.
Фильтр по TCP-флагам прямо в tcpdump
Иногда полезно захватить только пакеты с определенными флагами. Например, только пакеты с флагом RST, чтобы сразу понять, летают ли сбросы:
tcpdump -i eth0 -n "tcp[tcpflags] & tcp-rst != 0"Только SYN-пакеты - удобно для отслеживания попыток установить соединение:
tcpdump -i eth0 -n "tcp[tcpflags] & tcp-syn != 0"Комбинация RST или FIN для мониторинга завершений соединений к прокси:
tcpdump -i eth0 -n "host 203.0.113.10 and (tcp[tcpflags] & (tcp-rst|tcp-fin) != 0)"Wireshark: чтение дампа как открытой книги
tcpdump ловит, Wireshark читает. Это графический анализатор с богатейшей системой фильтров отображения и декодеров протоколов. Открываете сохраненный pcap-файл и начинаете расследование. Разберем инструменты, которые действительно нужны для нашей задачи.
Фильтры отображения против фильтров захвата
Важно не путать. Фильтр захвата (тот, что в tcpdump) отсеивает пакеты до записи - что не поймано, того нет. Фильтр отображения в Wireshark - это линза: он лишь скрывает лишнее из уже загруженного файла, ничего не удаляя. Синтаксис у них разный. Ниже - фильтры именно отображения.
Базовые фильтры отображения
Показать только трафик к конкретному IP:
ip.addr == 203.0.113.10Только TCP-порт прокси:
tcp.port == 8080Комбинация хоста и порта:
ip.addr == 203.0.113.10 && tcp.port == 8080Показать только пакеты с флагом RST - мгновенно видно все сбросы соединений:
tcp.flags.reset == 1Только пакеты с FIN:
tcp.flags.fin == 1Только SYN без ACK - попытки открыть соединение:
tcp.flags.syn == 1 && tcp.flags.ack == 0Поиск CONNECT и HTTP-заголовков
Чтобы найти в дампе сам запрос CONNECT:
http.request.method == "CONNECT"Ответ прокси об установке туннеля виден как HTTP-ответ. Отфильтровать все HTTP-запросы:
http.requestВсе HTTP-ответы с кодами:
http.responseFollow TCP Stream: собираем разговор воедино
Это, возможно, самая ценная функция Wireshark для нашей задачи. Правый клик по любому пакету соединения, затем Follow, затем TCP Stream. Wireshark соберет весь двусторонний обмен в одно окно, где данные клиента и сервера показаны разными цветами. Для незашифрованного трафика вы увидите чистый текст: запрос CONNECT, ответ прокси, а дальше нечитаемые байты TLS.
Именно в Follow Stream вы наглядно видите разрыв на CONNECT. Первые строки читаются как человеческий текст, затем начинается зашифрованная область. Это подтверждает: туннель установлен, дальше идет шифрование, и без ключей глубже не заглянуть - что абсолютно нормально.
Чтение TLS-хендшейка б��з расшифровки
Даже не имея ключей, TLS-хендшейк рассказывает многое. Отфильтруйте записи рукопожатия:
tls.handshakeНайти ClientHello, где клиент представляется серверу:
tls.handshake.type == 1Найти ServerHello, ответ сервера:
tls.handshake.type == 2Что дает эта пара? Если вы видите ClientHello, но никогда не видите ServerHello - сервер не ответил на рукопожатие. Причина: либо целевой сервер недоступен за прокси, либо разрыв произошел до ответа. Если видите оба, но затем разрыв - проблема глубже, уже в защищенном обмене или на уровне приложения.
Внутри ClientHello без всякой расшифровки читается поле SNI - имя хоста, к которому идет обращение:
tls.handshake.extensions_server_name == "api.example.com"Вы также видите предлагаемые версии TLS и наборы шифров. Если сервер отвечает Alert вместо ServerHello, значит рукопожатие отклонено - например, несовместимость версий или шифров. Фильтр для алертов:
tls.alert_messageДиагностика по дампу: кто именно оборвал соединение
Мы подошли к сердцу статьи. Соединение упало - вопрос в том, кто его оборвал и почему. TCP оставляет улики, и по ним можно вынести вердикт. Разберем ключевые сигналы.
Нормальное завершение: FIN
Штатное закрытие соединения происходит через обмен пакетами FIN. Одна сторона говорит я закончил передачу, другая подтверждает и тоже отправляет FIN. Это вежливое прощание. Если в дампе вы видите аккуратный обмен FIN-ACK-FIN-ACK, соединение закрылось корректно. Вопрос лишь в том, ожидал ли этого закрытия ваш клиент. Если сервер отправил FIN, отдав ответ полностью, все хорошо. Если FIN пришел посреди ожидаемых данных - сервер закрыл раньше времени.
Аварийное завершение: RST
Флаг RST - это грубый обрыв. Не прощание, а хлопок дверью. RST означает: это соединение недействительно, немедленно забудь о нем. Причины бывают разные:
- Порт закрыт - никто не слушает на той стороне. RST приходит почти мгновенно после SYN.
- Приложение на той стороне аварийно закрыло сокет.
- Промежуточное устройство (фаервол, балансировщик, сам прокси) принудительно сбросило соединение по таймауту или политике.
- Одна из сторон получила пакет для соединения, о котором уже забыла.
Ключ к разгадке - кто отправил RST. Смотрите на source IP пакета с RST. Если RST пришел с IP прокси - оборвал прокси или что-то между прокси и вами. Если с IP целевого сервера - значит сегмент прокси-сервер дошел до сервера, и оборвал уже он или устройство рядом с ним.
Но помните про два сегмента. Снимая дамп на клиенте, вы видите RST только с IP прокси, потому что напрямую с сервером вы не общаетесь - между вами прокси. Чтобы понять, что творится в сегменте Б, нужен дамп на стороне прокси. Об этом мы поговорим в разделе про чеклист.
Повторные передачи: retransmission
Wireshark автоматически помечает повторные передачи. Фильтр:
tcp.analysis.retransmissionПовторная передача означает, что отправитель не получил ACK на отправленный сегмент в срок и шлет его снова. Единичные ретрансмиссии - норма для интернета. Но лавина ретрансмиссий - симптом потери пакетов на пути. Особенно характерно для мобильных и нестабильных сетей.
Связанные полезные фильтры. Дубликаты ACK, сигнализирующие о пропущенном сегменте:
tcp.analysis.duplicate_ackВсе проблемные события, которые Wireshark смог распознать:
tcp.analysis.flagsЕсли вы видите серию ретрансмиссий, за которой следует RST, картина складывается: пакеты терялись, одна из сторон устала ждать и оборвала соединение. Это типичная история для плохого канала.
Zero Window: получатель захлебнулся
TCP имеет механизм управления потоком через окно приема. Если получатель не успевает обрабатывать данные, он объявляет zero window - буфер полон, притормози. Фильтр:
tcp.analysis.zero_windowZero window - это не сетевая потеря, а сигнал, что принимающее приложение медленно читает из сокета. Например, ваш клиент получает большой ответ, но обрабатывает его в один поток и не успевает. Отправитель ждет, окно не открывается, и в итоге может сработать таймаут. Если после zero window идет window update, все нормализовалось. Если после zero window тишина и затем RST - получатель завис или упал.
Родственный сигнал - window full, когда отправитель уперся в объявленное окно и не может слать дальше:
tcp.analysis.window_fullМатрица вердиктов
Соберем логику в практический фреймворк. Смотрите на последние пакеты ж��вого соединения перед обрывом:
- SYN есть, SYN-ACK нет, потом RST или тишина. Соединение не установилось. Целевая точка недоступна или порт закрыт. При работе через прокси RST придет от прокси, если недоступен сервер за ним.
- Установка прошла, CONNECT отправлен, ответа нет. Прокси принял команду, но не смог достучаться до целевого сервера или тот молчит. Ждите таймаут.
- ClientHello есть, ServerHello нет. Целевой сервер не ответил на рукопожатие. Проблема в сегменте прокси-сервер.
- Данные шли, затем RST от сервера. Сервер аварийно закрыл соединение - перегрузка, ошибка приложения, таймаут на его стороне.
- Данные шли, затем FIN от сервера посреди ответа. Сервер закрыл штатно, но раньше, чем клиент ожидал - вероятно, лимит на размер ответа или таймаут запроса.
- Лавина retransmission, затем RST. Потери в канале. Ищите проблему в сети - мобильное соединение, перегруженный маршрут.
- Zero window, затем тишина. Ваш клиент не читал данные достаточно быстро. Проблема на вашей стороне в обработке.
Расшифровка своего трафика через SSLKEYLOGFILE
Иногда одних метаданных мало - нужно увидеть содержимое зашифрованного обмена. Это законно и корректно только тогда, когда трафик ваш собственный: ваш клиент, ваши ключи, ваше приложение. Мы не перехватываем чужое и не подменяем сертификаты. Мы просим наш собственный клиент любезно записать сессионные ключи в файл, чтобы затем скормить их Wireshark.
Как это работает
Многие клиентские библиотеки TLS поддерживают переменную окружения SSLKEYLOGFILE. Если она задана, библиотека дописывает в указанный файл секреты сессий в стандартном формате. Wireshark умеет читать этот файл и расшифровывать соответствующие сессии в дампе. Никакой магии и никакого взлома - клиент сам добровольно отдает свои ключи, потому что вы, владелец клиента, так распорядились.
Пример для командной строки и браузеров на движке с поддержкой
Установка переменной перед запуском приложения в Unix-подобной системе:
export SSLKEYLOGFILE=/home/user/tls-keys.logЗапуск клиента, например curl, поддерживающего эту переменную при сборке с подходящей библиотекой:
SSLKEYLOGFILE=/home/user/tls-keys.log curl -x http://203.0.113.10:8080 https://api.example.com/statusЗдесь флаг -x задает прокси Proxeon, а SSLKEYLOGFILE заставляет записать ключи сессии. Параллельно снимаете дамп через tcpdump. После этого у вас есть и pcap, и файл ключей.
Подключение ключей в Wireshark
В Wireshark откройте настройки, найдите раздел протокола TLS, укажите путь к файлу ключей в поле для лог-файла предмастер-секретов. После этого перечитайте дамп. Ранее нечитаемые TLS-записи станут расшифрованными: вы увидите настоящие HTTP-запросы и ответы внутри туннеля. Теперь Follow TLS Stream покажет прикладной обмен целиком.
Важные границы применимости
- Расшифровывается только тот трафик, чьи ключи попали в файл. Чужие сессии остаются зашифрованными - и это правильно.
- Ключи чувствительны. Файл tls-keys.log фактически открывает содержимое ваших сессий. Храните его как секрет, удаляйте после отладки.
- Метод предназначен для отладки собственных приложений, а не для наблюдения за чужим трафиком. Это принципиальная этическая и юридическая граница.
Типичные картины обрывов и как их читать
Теория без узнаваемых паттернов быстро выветривается. Разберем несколько характерных сценариев, которые вы будете встречать снова и снова. Научитесь узнавать их с первого взгляда.
Таймаут коннекта: сервер за прокси недоступен
Картина в дампе на клиенте: TCP к прокси установился нормально, клиент отправил CONNECT, и наступила тишина. Ответа 200 от прокси нет. Спустя время либо приходит RST от прокси, либо приложение само закрывает соединение по своему таймауту.
Что это значит: прокси принял вашу команду, попытался открыть сегмент Б к целевому серверу, но тот не ответил. Целевой сервер лежит, порт закрыт, или маршрут до него оборван. Ваша сторона и прокси работают штатно. Действие: проверить доступность целевого хоста, при необходимости снять дамп на стороне прокси, чтобы увидеть сегмент Б.
Обрыв в середине ответа
Картина: туннель установлен, TLS отработал, пошли данные, часть ответа получена, и вдруг FIN или RST от стороны сервера. Клиент получил неполный ответ и ругается на усеченный контент.
Если это FIN, сервер закрыл штатно, но преждевременно - возможно, сработал лимит времени генерации ответа или ограничение размера на его стороне. Если это RST, сервер или устройство рядом с ним аварийно оборвали. Действие: если проблема повторяется н�� больших ответах - искать таймауты и лимиты. Расшифровка своего трафика через SSLKEYLOGFILE поможет увидеть, был ли получен HTTP-заголовок и сколько тела успело прийти.
Потери в мобильной сети
Картина: множество пакетов помечены как retransmission, встречаются duplicate ack, наблюдаются заметные скачки времени между пакетами. Соединение либо мучительно медленное, либо в итоге рвется по таймауту.
Это классика нестабильного радиоканала. Пакеты теряются, TCP их пересылает, скорость падает. Мобильные сети также склонны разрывать долго простаивающие соединения через NAT-таймауты промежуточного оборудования оператора: посреди тишины внезапно прилетает RST, когда одна из сторон пытается возобновить обмен по соединению, которое оператор уже забыл. Действие: настроить разумные keep-alive и таймауты, повторные попытки на уровне приложения, не держать долгие простаивающие соединения.
Прокси недоступен вовсе
Картина: клиент шлет SYN на IP и порт прокси, но не получает SYN-ACK. Либо тишина и ретрансмиссии SYN, либо мгновенный RST. Если тишина - между вами и прокси что-то фильтрует пакеты или прокси не слушает. Если мгновенный RST - на этом порту никто не отвечает. Действие: проверить адрес и порт прокси, сетевую доступность, корректность конфигурации.
Медленный клиент: zero window
Картина: обмен идет, но периодически клиент объявляет zero window, отправитель приостанавливается, затем window update возобновляет поток. Если такое повторяется часто, ваше приложение читает из сокета медленнее, чем сервер отдает. Действие: оптимизировать обработку ответа, читать поток в отдельном потоке, увеличить буферы.
Типичные ошибки при снятии и чтении дампа
Опыт - это коллекция набитых шишек. Соберем самые частые ошибки, чтобы вы их не повторяли.
- Снимать дамп не там. Ищете обрыв в сегменте прокси-сервер, а дамп сняли на клиенте, где этого сегмента не видно вовсе. Всегда думайте, какой сегмент вам нужен, и снимайте дамп в правильной точке.
- Захватывать все подряд. Без фильтра на нагруженном сервере вы получите гигабайты и утонете в них. Фильтруйте по хосту и порту с самого начала.
- Обрезанный snaplen там, где нужны данные. Если хотите видеть содержимое, а поставили короткий snaplen, полезная нагрузка будет усечена, и Follow Stream покажет обрывки.
- Резолвинг имен включен. Забыли флаг -n, и tcpdump тормозит на DNS, искажая тайминги. Всегда -n при захвате.
- Игнорировать направление RST. Видят RST и делают вывод, не посмотрев, кто его отправил. Source IP пакета RST - половина ответа.
- Путать штатный FIN с аварией. FIN - это нормальное закрытие. Паниковать надо не от самого FIN, а от FIN, пришедшего раньше ожидаемого конца данных.
- Забывать про часовые пояса и точное время. Логи приложения и дамп должны быть синхронизированы по времени, иначе вы не найдете нужный момент. Держите NTP в порядке.
- Хранить файл ключей SSLKEYLOGFILE. После отладки он должен быть удален. Это секрет, раскрывающий содержимое ваших сессий.
- Делать выводы по одному соединению. Интермиттирующие проблемы требуют статистики. Один упавший запрос может быть случайностью, паттерн из десятка - диагнозом.
Инструменты и ресурсы инженера
Соберем арсенал, который стоит иметь под рукой при работе с прокси-трафиком.
Захват
- tcpdump - основной инструмент захвата на серверах и в консоли. Легкий, всегда доступный, гибкий фильтр.
- dumpcap - консольная утилита из комплекта Wireshark, специально заточенная под эффективный захват с ротацией.
- tshark - консольный Wireshark. Позволяет применять фильтры отображения без графики, удобен для скриптов и удаленных серверов.
Анализ
- Wireshark - графический анализатор, декодеры сотен протоколов, мощная система фильтров, Follow Stream, статистика по соединениям.
- Экспертная информация Wireshark - встроенная панель, подсвечивающая аномалии: ретрансмиссии, сбросы, zero window. Начинайте расследование именно с нее.
- Статистика конверсаций - таблица всех TCP-соединений в дампе с байтами и длительностью. Быстро видно, какое соединение аномально короткое.
Полезные приемы командной строки
Быстро посмотреть содержимое pcap в консоли через tshark с фильтром отображения:
tshark -r dump.pcap -Y "tcp.flags.reset == 1"Вывести только запросы CONNECT из файла:
tshark -r dump.pcap -Y "http.request.method == \"CONNECT\""Посмотреть все ретрансмиссии:
tshark -r dump.pcap -Y "tcp.analysis.retransmission"Эти команды бесценны, когда графики нет, а разобраться надо здесь и сейчас, по ssh.
Кейсы и результаты применения
Ничто не убеждает лучше живых историй. Приведу собирательные кейсы, отражающие реальную инженерную практику диагностики прокси-трафика.
Кейс 1: пять процентов запросов падают ночью
Команда интеграции жаловалась: около пяти процентов запросов к внешнему API через прокси падали с усеченным ответом, преимущественно ночью. Логи приложения показывали неполный контент. Логи прокси - установленные туннели без ошибок.
Сняли дамп на клиенте с кольцевой ротацией на несколько часов и точной меткой ошибки из лога. В момент инцидента увидели: туннель установлен, TLS отработал, часть тела ответа пришла, затем FIN от прокси. Расшифровка своего трафика через SSLKEYLOGFILE показала: приходил корректный HTTP-заголовок с указанием размера тела, но тело обрывалось на середине. Вывод: целевой сервер закрывал соединение по своему таймауту генерации больших ночных отчетов. Решение на стороне интеграции - запрашивать данные постранично меньшими порциями. Проблема ушла полностью.
Кейс 2: таинственный мгновенный RST
Другой инженер получал мгновенный сброс сразу после отправки CONNECT для одного конкретного хоста, тогда как для других хостов все работало. Первое подозрение падало на прокси.
Дамп на клиенте показал: CONNECT ушел, и почти мгновенно вернулся RST с IP прокси. Но мгновенность настораживала - обычно недоступность сервера дает таймаут, а не мгновенный сброс. Сняли дамп на стороне прокси и увидели сегмент Б: прокси открывал соединение к целевому хосту на нужный порт, а целевой сервер отвечал RST на SYN - порт был закрыт. Прокси честно транслировал этот отказ клиенту. Оказалось, целевой сервис недавно сменил порт. Вывод: мгновенный RST - это чаще всего закрытый порт, а не проблема прокси. Правильный порт восстановил работу.
Кейс 3: деградация в мобильном сегменте
Приложение на мобильных устройствах, работающее через прокси, у части пользователей регулярно теряло соединение. Дамп с устройства в проблемной зоне покрытия показал классическую картину: серии ретрансмиссий, дубликаты ACK, растущие интервалы, и в финале RST после долгого простоя - результат NAT-таймаута у оператора.
Вывод: сеть, а не прокси и не сервер. Решение - на уровне приложения ввели адаптивные повторные попытки, разумные keep-alive и грациозную обработку разрывов с переустановкой соединения. Число видимых пользователю ошибок упало в разы, хотя сам радиоканал остался прежним. Пакетный дамп позволил не тратить время на ложные гипотезы о прокси и сфокусироваться на реальной причине.
Общий инсайт из кейсов
Во всех трех историях дамп сэкономил недели переписки и взаимных обвинений между командами. Пакеты не лгут. Как только на столе появляется дамп с направлением RST, наличием или отсутствием ServerHello и картиной ретрансмиссий, спор о виновнике завершается за минуты. Это и есть главная ценность метода: он переводит диагностику из плоскости мнений в плоскость фактов.
Чеклист снятия дампа для обращения в поддержку
Когда вы обращаетесь в поддержку - хоть провайдера прокси Proxeon, хоть владельца целевого API - грамотно снятый дамп ускоряет решение в разы. Вот чеклист, который стоит выполнить перед обращением.
Перед захватом
- Зафиксируйте точное время начала диагностики и синхронизируйте часы по NTP на всех участвующих машинах.
- Определите точки захвата: как минимум на клиенте, по возможности - и на стороне, где у вас есть доступ.
- Соберите вводные: IP и порт прокси, имя и порт целевого хоста, ожидаемое и фактическое поведение.
Во время захвата
- Запустите tcpdump с фильтром по хосту прокси и целевому порту, с полным snaplen и ротацией:
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 - Воспроизведите проблему и запишите точное время инцидента с миллисекундами из лога приложения.
- Не забудьте параллельно сохранить логи приложения за тот же интервал.
Что приложить к обращению
- Сам pcap-файл, обрезанный до релевантного интервала времени, чтобы не отправлять гигабайты.
- Точные временные метки инцидента и часовой пояс.
- IP и порт прокси, имя и порт целевого хоста, описание сценария.
- Фрагмент логов приложения с ошибкой.
- Ваш предварительный анализ: кто отправил RST или FIN, был ли ServerHello, наблюдались ли ретрансмиссии. Это показывает, что вы сделали домашнюю работу.
Как обрезать pcap до нужного интервала
Огромный файл можно урезать по времени через tshark или editcap. Пример вырезания по номеру пакетов или по фильтру:
tshark -r big.pcap -Y "frame.time >= \"2026-01-01 03:00:00\" && frame.time <= \"2026-01-01 03:05:00\"" -w small.pcapТакой аккуратный, сфокусированный дамп поддержка обработает быстро, потому что ей не придется искать иголку в стоге сена.
FAQ: частые вопросы по дампам через прокси
Почему в дампе HTTPS-трафика через прокси я вижу только CONNECT и дальше нечитаемое?
Потому что после установки туннеля прокси лишь пересылает зашифрованные TLS-байты, не имея к ним ключей. Открытым текстом идет только команда CONNECT с именем хоста и ответ прокси об установке. Все остальное защищено шифрованием - и это ровно то, ради чего HTTPS существует. Чтобы увидеть содержимое собственного трафика, используйте SSLKEYLOGFILE.
Как понять, что соединение оборвал именно целевой сервер, а не прокси?
Смотрите на source IP пакета с RST или FIN. Но помните про два сегмента: на дампе с клиента вы видите только IP прокси, потому что напрямую с сервером не общаетесь. Чтобы точно приписать обрыв целевому серверу, нужен дамп на стороне прокси, где виден сегмент прокси-сервер. Если RST в сегменте Б приходит с IP сервера - оборвал он.
Чем retransmission отличается от RST по смыслу диагностики?
Retransmission - это повторная отправка неподтвержденного сегмента, признак потери пакетов в канале, но соединение еще живо и борется. RST - это завершение, приказ забыть соединение. Лавина ретрансмиссий, переходящая в RST, читается как: канал терял пакеты, сторона устала ждать и оборвала. Единичные ретрансмиссии - норма интернета.