Когда соединение устанавливается через раз или запрос зависает без ответа, журнал приложения обычно молчит: с его точки зрения ничего не произошло. Ответ даёт разбор пакетов на сетевом интерфейсе. Утилита tcpdump показывает обмен таким, каким его видит ядро, и позволяет отличить проблему приложения от проблемы сети. Разбираем, как устроен захват, как составлять фильтры, как читать рукопожатие TCP и какие выводы следуют из типовых картин обмена.
Как устроен захват и что влияет на результат
Программа переводит интерфейс в режим неразборчивой приёмки и получает копии пакетов из точки, расположенной между стеком протоколов и драйвером. Отсюда следуют два ограничения, которые стоит учитывать до начала разбора.
Первое: пакеты, отправленные самим хостом, видны после прохождения исходящих правил фильтрации, а полученные до прохождения входящих. Поэтому отказ по правилам сетевого экрана выглядит как отсутствие ответа при наличии запроса.
Второе: аппаратное ускорение меняет картину. При включённой сборке крупных сегментов ядро передаёт драйверу один большой блок, и в захвате виден пакет размером в десятки килобайт, хотя в сеть ушли обычные сегменты по полторы тысячи байт. Для корректного разбора ускорение отключают на время диагностики.
ethtool -k eth0 | grep -E 'segmentation|receive-offload'
sudo ethtool -K eth0 tso off gso off gro off
sudo tcpdump -i eth0 -nn -c 20
Параметр -n отключает преобразование адресов в имена, и это не только ускоряет вывод, но и убирает лишние обращения к службе DNS во время захвата. Параметр -c ограничивает число пакетов, что удобно для быстрой проверки.
Выбор интерфейса имеет значение. Для трафика между контейнерами и хостом подходит интерфейс моста или пары устройств, для внешнего обмена физический интерфейс.
tcpdump -D
ip -br link show
Для размеченного трафика захват ведут либо на родительском устройстве, где видны все метки, либо на устройстве конкретной VLAN. Первый вариант показывает, доходит ли кадр с нужной меткой, второй что происходит после разбора. При диагностике моста данные снимают на мосту и на порту одновременно: сравнение записей показывает, где теряется кадр.
Синтаксис фильтров и типовые выражения
Фильтр задаётся выражением после параметров и разбирается до начала захвата, поэтому лишние пакеты просто не попадают в вывод. Выражения строятся из указаний на хост, сеть, порт и протокол, объединённых логическими связками.
sudo tcpdump -i eth0 -nn host 192.168.10.20
sudo tcpdump -i eth0 -nn src host 10.0.0.5 and dst port 443
sudo tcpdump -i eth0 -nn net 192.168.10.0/24 and not port 22
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-syn != 0'
sudo tcpdump -i eth0 -nn icmp
Связки and, or и not комбинируют условия, а выражения в кавычках защищают специальные символы от разбора оболочкой. Фильтр по флагам TCP записывается обращением к байтам заголовка и позволяет отобрать только пакеты начала соединения.
Формат вывода настраивается отдельными параметрами. Флаг -tttt добавляет полную дату и время, что необходимо при сопоставлении записи с журналами приложений, флаг -e показывает адреса второго слоя, а флаг -v раскрывает дополнительные поля заголовков, включая размер окна и параметры согласования.
sudo tcpdump -i eth0 -nn -tttt -e -c 5 host 192.168.10.5
Корректность фильтра стоит проверять заранее: неверное выражение приводит к сообщению об ошибке разбора, а слишком узкое к пустому выводу, который легко принять за отсутствие трафика.
Полезный приём состоит в том, чтобы начинать с широкого фильтра и сужать его. Захват всего обмена по одному адресу показывает картину целиком, после чего становится ясно, какой протокол и какой порт рассматривать подробнее.
Отрицание помогает убрать шум. Исключение порта службы мониторинга и широковещательного обмена сокращает вывод в разы и не маскирует при этом искомое событие.
Запись в файл, ограничение размера и ротация
Разбор на экране подходит для короткой диагностики. Когда событие происходит редко, захват пишут в файл и ограничивают его размер, чтобы не заполнить диск.
sudo tcpdump -i eth0 -nn -s 0 -w /tmp/cap.pcap -C 10 -W 5 -Z root
sudo tcpdump -i eth0 -nn -r /tmp/cap.pcap0 host 192.168.10.20
Параметр -s 0 задаёт захват пакета целиком, параметр -C ограничивает размер одного файла в мегабайтах, параметр -W число файлов в цикле. При таком наборе запись идёт по кругу, и старые файлы заменяются новыми, что удобно для ожидания редкого сбоя.
Параметр -Z задаёт пользователя, от имени которого ведётся запись после открытия файла. Ограничение захвата по числу пакетов вместо размера применяется, когда нужно получить короткий срез для быстрой проверки.
sudo tcpdump -i eth0 -nn -c 500 -w /tmp/short.pcap
Чтение файла выполняется тем же инструментом с параметром -r, и к нему можно применять любые фильтры. Это удобнее, чем запускать захват заново: данные уже собраны, и их можно рассматривать под разными углами.
При длительном ожидании события удобно сочетать запись в файл с фильтром по условию, которое заведомо редко выполняется, например по конкретному коду ответа или по флагу сброса. Такой захват не заполняет диск обычным обменом и срабатывает только в момент интересующего события.
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0' -w /tmp/resets.pcap -C 1 -W 3
Для передачи файла на рабочую станцию с графическим анализатором подходит обычное копирование по защищённому протоколу. Формат pcap понимают большинство инструментов разбора, и дополнительного преобразования не требуется.
Чтение рукопожатия TCP и признаки проблем с соединением
Установка соединения состоит из трёх пакетов: клиент отправляет запрос с флагом SYN, сервер отвечает SYN и ACK, клиент подтверждает передачей ACK. В выводе это выглядит предсказуемо, и отклонения от картины сразу заметны.
12:01:03.101 IP 192.168.10.20.51844 > 192.168.10.5.443: Flags [S], seq 1234, win 64240
12:01:03.102 IP 192.168.10.5.443 > 192.168.10.20.51844: Flags [S.], seq 900, ack 1235, win 65160
12:01:03.103 IP 192.168.10.20.51844 > 192.168.10.5.443: Flags [.], ack 1, win 502
Флаги выводятся в сокращённой записи: S означает запрос соединения, точка подтверждение, P передачу данных, F завершение, R принудительный разрыв. Отсутствие второго пакета означает, что сервер не ответил, и причину стоит искать в доступности порта и правилах фильтрации.
Ответ с флагом R вместо SYN и ACK означает, что порт не прослушивается либо соединение сброшено намеренно. Повторяющиеся пакеты SYN с одинаковым номером последовательности говорят о том, что клиент не получил ответа и пробует снова, а интервалы между повторами растут.
Завершение соединения в норме состоит из обмена FIN и ACK с обеих сторон. Картина, в которой одна сторона отправляет FIN, а вторая отвечает RST, указывает на аварийное закрытие, обычно из-за завершения процесса или истечения таймаута.
Отдельно рассматривают повторы передачи. Одинаковые номера последовательности в нескольких пакетах подряд означают, что данные отправлены заново, поскольку подтверждение не пришло вовремя.
sudo tcpdump -i eth0 -nn 'tcp[tcpflags] & tcp-rst != 0'
sudo tcpdump -i eth0 -nn host 192.168.10.5 and port 443 | grep -c 'Flags \[S\]'
Первая команда отбирает только сбросы соединений, вторая позволяет грубо оценить число попыток установки соединения за период.
Разбор DNS, ARP и ICMP для локальных проблем
Часть обращений выглядит как недоступность службы, хотя причина лежит в разрешении имени или в определении адреса соседа. Захват по порту службы имён показывает, уходит ли запрос и приходит ли ответ.
sudo tcpdump -i eth0 -nn port 53
sudo tcpdump -i eth0 -nn 'udp[2:2] = 53'
В выводе видны имя из запроса и набор ответов. Отсутствие ответа при наличии запроса указывает на недоступность службы имён либо на фильтрацию, а ответ с пустым набором записей означает, что имя не найдено.
Для определения адреса соседа используется протокол разрешения адресов, и его обмен хорошо виден в захвате.
sudo tcpdump -i eth0 -nn arp
Запросы без ответов означают, что узел не отвечает на уровне второго слоя: машина выключена, порт коммутатора заблокирован либо адрес задан неверно. Ответ от неожиданного MAC-адреса признак дублирования адреса в сети.
Сообщения протокола ICMP объясняют часть отказов. Ответ о недостижимости сети или порта приходит вместо данных и виден в захвате как отдельный пакет.
sudo tcpdump -i eth0 -nn 'icmp[icmptype] == icmp-unreach'
Слишком большие пакеты, которые не проходят по пути, приводят к сообщениям о необходимости уменьшить размер. Такое сообщение должно возвращаться отправителю, и если промежуточное устройство его отбрасывает, соединение зависает на передаче крупных ответов. Проверка выполняется пакетом заданного размера с запретом фрагментации.
ping -M do -s 1472 192.168.10.5
Анализ шифрованного обмена без доступа к содержимому
Содержимое соединений по TLS в захвате не видно, но обмен метаинформацией остаётся открытым и часто достаточен для диагностики. В первом сообщении клиента присутствует запрашиваемое имя сервера, и его можно извлечь.
sudo tcpdump -i eth0 -nn -A 'tcp[13] == 24' | grep -a -o '[a-z0-9.-]*\.example\.ru'
Время между началом рукопожатия TCP и первой передачей данных показывает, сколько занимает согласование параметров шифрования. Задержка в сотни миллисекунд на этом этапе характерна для перегруженного сервера либо для обмена с далёким узлом.
Полезно также сравнивать объём переданных данных в обе стороны. Соединение, в котором клиент отправил несколько пакетов и не получил ответа, отличается от соединения, где обмен шёл и прервался на крупном ответе. Во втором случае причину стоит искать в размере ответа и в доступном времени ожидания.
sudo tcpdump -i eth0 -nn -q host 192.168.10.5 | awk '{print $3,$5}' | sort | uniq -c | sort -rn | head
Такая группировка показывает, между какими парами адресов и портов идёт основной обмен, и помогает выбрать следующий шаг диагностики.
Разница между отметками первого пакета рукопожатия TCP и ответа сервера соответствует удвоенному времени прохождения пути, и значение заметно выше ожидаемого указывает на перегрузку канала или на лишний промежуточный узел.
Типовые ошибки при захвате и правила интерпретации
Первая ошибка состоит в выборе неверного интерфейса. При наличии моста захват на физическом порту показывает не весь обмен, а захват на мосту не показывает трафик между портами внутри него. Перед началом стоит убедиться, какой путь проходит пакет.
Вторая ошибка связана с ожиданием содержимого там, где его нет. Трафик по шифрованному соединению не читается, и попытки найти в нём строки запроса приводят к ложным выводам. Для разбора таких случаев применяют журнал приложения либо тестовый стенд без шифрования.
Третья ошибка, интерпретация крупных пакетов как признака неисправности. При включённом ускорении ядро передаёт драйверу собранные блоки, и размер в выводе не соответствует тому, что ушло в сеть. Проверка состояния ускорения до начала разбора снимает вопрос.
Четвёртая ошибка связана с влиянием самого захвата на систему. При высокой нагрузке обработка каждого пакета копией в пользовательский процесс увеличивает задержки, и картина меняется. Ограничение числа пакетов и использование фильтра снижают влияние.
sudo tcpdump -i eth0 -nn -s 96 -w /tmp/heads.pcap -c 10000
Захват только заголовков, без полного содержимого, уменьшает объём данных и нагрузку на диск, и для анализа установлений соединений этого достаточно.
Пятая ошибка связана с правами: запуск от имени обычного пользователя завершается отказом с сообщением о недоступности интерфейса. Постоянно выдавать привилегии не стоит, безопаснее задать файлу утилиты специальные возможности один раз.
sudo setcap cap_net_raw,cap_net_admin=eip /usr/bin/tcpdump
getcap /usr/bin/tcpdump
После этого захват работает без повышения привилегий, но обновление пакета сбрасывает настройки, и их приходится применять заново.
Завершая разбор, стоит зафиксировать три вещи: команду захвата с фильтром, интервал времени, к которому относится запись, и вывод о том, на каком этапе обмен прерывается. Такой записи достаточно, чтобы продолжить диагностику позже или передать её коллеге без повторного сбора данных.