tcpdump и Wireshark — захват и анализ трафика
Когда стандартные инструменты (ping, curl, dig, ss) не дают ответа на «почему сеть не работает», остаётся один последний инструмент — захват самого трафика. Вы буквально смотрите на байты, которые летят по сети, и понимаете, что не так. Это уровень нинзя сетевой диагностики, и в этом уроке разберём два главных инструмента: tcpdump (CLI) и Wireshark (GUI).
tcpdump запускается на удалённом сервере по SSH и пишет в pcap-файл. Wireshark открывает pcap локально и даёт интерактивный анализ с фильтрами, графиками, расшифровкой протоколов. Вместе они — стандарт de facto в network troubleshooting.
tcpdump — minimum viable example
tcpdump слушает сетевой интерфейс и выводит каждый пакет. Это требует root-прав (raw sockets).
# Самый базовый запуск (выведет всё на eth0):
sudo tcpdump -i eth0
# tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
# listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
# 14:30:45.123456 IP 10.0.0.42.45678 > 142.250.74.110.443: Flags [S], seq 12345, win 65535, length 0
# 14:30:45.156789 IP 142.250.74.110.443 > 10.0.0.42.45678: Flags [S.], seq 67890, ack 12346, win 65535, length 0
# 14:30:45.156823 IP 10.0.0.42.45678 > 142.250.74.110.443: Flags [.], ack 67891, win 65535, length 0
# 14:30:45.157234 IP 10.0.0.42.45678 > 142.250.74.110.443: Flags [P.], seq 12346:12400, ack 67891, win 65535, length 54
# ...
# Остановить -- Ctrl+C
Разберём output (один пакет):
14:30:45.123456 IP 10.0.0.42.45678 > 142.250.74.110.443: Flags [S], seq 12345, win 65535, length 0
14:30:45.123456— timestamp с микросекундами.IP— IPv4 (или IP6).10.0.0.42.45678— source IP.port.>— направление.142.250.74.110.443— destination IP.port (443 = HTTPS).Flags [S]— TCP flags. S = SYN. Это первый пакет TCP-handshake.seq 12345— sequence number.win 65535— receive window.length 0— payload длина (SYN не несёт data).
TCP flags:
- S = SYN (handshake initiation)
- A или . = ACK
- F = FIN (closing)
- R = RST (reset)
- P = PSH (push — сигнал передать сразу)
- U = URG (urgent)
[S.] = [SYN+ACK]. [F.] = [FIN+ACK]. И т.д.
Так что в нашем примере:
Flags [S]— клиент шлёт SYN на сервер.Flags [S.]— сервер отвечает SYN-ACK.Flags [.]— клиент шлёт ACK. TCP handshake завершён.Flags [P.] length 54— клиент шлёт первые 54 байта данных (TLS Client Hello).
Видно весь handshake глазами.
Фильтры — основа эффективного capture
tcpdump без фильтров — это потоп пакетов. Эффективно использовать — значит фильтровать по конкретным критериям. Это BPF (Berkeley Packet Filter) синтаксис.
По хосту
# Все пакеты к/от конкретного IP:
sudo tcpdump -i eth0 host 142.250.74.110
# Только исходящие:
sudo tcpdump -i eth0 src host 10.0.0.42
# Только входящие:
sudo tcpdump -i eth0 dst host 10.0.0.42
# По имени (резолвится в IP при запуске):
sudo tcpdump -i eth0 host github.com
По порту
# Весь HTTP-трафик:
sudo tcpdump -i eth0 port 80
# Только HTTPS:
sudo tcpdump -i eth0 port 443
# DNS-запросы:
sudo tcpdump -i eth0 port 53
# Диапазон портов:
sudo tcpdump -i eth0 portrange 8000-9000
По протоколу
# Только TCP:
sudo tcpdump -i eth0 tcp
# Только UDP:
sudo tcpdump -i eth0 udp
# Только ICMP (ping):
sudo tcpdump -i eth0 icmp
# ARP:
sudo tcpdump -i eth0 arp
Комбинации
# HTTPS-трафик к конкретному серверу:
sudo tcpdump -i eth0 'host 142.250.74.110 and port 443'
# DNS и HTTPS:
sudo tcpdump -i eth0 'port 53 or port 443'
# Не SSH (чтобы не засорять output при SSH-сессии):
sudo tcpdump -i eth0 'not port 22'
# TCP с конкретного source:
sudo tcpdump -i eth0 'src host 10.0.0.42 and tcp'
# Только SYN (открытие соединения):
sudo tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack = 0'
Подсети
# Все в подсети:
sudo tcpdump -i eth0 net 10.0.0.0/24
# От любого внешнего к нам:
sudo tcpdump -i eth0 'src net not 10.0.0.0/8 and dst host 10.0.0.42'
Полезные флаги tcpdump
# -n -- не резолвить имена в IP (быстрее, без зависимости от DNS):
sudo tcpdump -n -i eth0
# -nn -- не резолвить порты (видеть номера, а не "https"/"ssh"):
sudo tcpdump -nn -i eth0
# -v / -vv / -vvv -- verbose level. Больше деталей.
sudo tcpdump -nn -v -i eth0
# -X -- hex и ASCII dump каждого пакета:
sudo tcpdump -nn -X -i eth0 'port 80'
# -A -- ASCII только (для plain-text протоколов):
sudo tcpdump -nn -A -i eth0 'port 80'
# -s 0 -- захватывать весь пакет (по умолчанию иногда обрезают):
sudo tcpdump -s 0 -i eth0
# -c N -- остановиться после N пакетов:
sudo tcpdump -nn -c 100 -i eth0
# -i any -- слушать все интерфейсы сразу:
sudo tcpdump -nn -i any
# -w file.pcap -- писать в файл, не в stdout:
sudo tcpdump -nn -i eth0 -w /tmp/capture.pcap
# -r file.pcap -- читать из файла:
tcpdump -nn -r /tmp/capture.pcap
# -D -- список доступных интерфейсов:
sudo tcpdump -D
Реальный пример: дебажим HTTP
Сценарий: API на порту 8080 не отвечает на запросы. Хотим увидеть, доходят ли SYN до сервера, что отвечает.
# На сервере (по SSH):
sudo tcpdump -nn -i any 'tcp and port 8080' -w /tmp/api-debug.pcap
# В другом терминале на клиенте:
curl http://server-ip:8080/
# В первом терминале -- Ctrl+C через несколько секунд
# Прочитать pcap:
tcpdump -nn -r /tmp/api-debug.pcap
Если pcap пустой — SYN от клиента не доходит. Скорее всего firewall или сетевая проблема.
Если SYN видны, но нет SYN-ACK — сервер получает, но не отвечает. Возможно, нет процесса на порту 8080 (lsof -iTCP:8080) или firewall блокирует на уровне OS (iptables).
Если есть SYN-ACK-ACK (handshake), но потом RST — приложение упало после accept-а.
# Только SYN-пакеты (открытие соединений):
tcpdump -nn -r /tmp/api-debug.pcap 'tcp[tcpflags] & tcp-syn != 0'
# Только RST (resets -- сервер отказывается):
tcpdump -nn -r /tmp/api-debug.pcap 'tcp[tcpflags] & tcp-rst != 0'
Wireshark — то же самое, но GUI
Wireshark — графический интерфейс к libpcap (то же, что использует tcpdump). Может работать в двух режимах:
- Live capture — читать пакеты в реальном времени с интерфейса.
- Offline analysis — открывать pcap-файлы.
Второй — стандарт workflow: на удалённом сервере запустить tcpdump -w capture.pcap, скачать файл локально и открыть в Wireshark.
# Захват на сервере:
sudo tcpdump -i eth0 -w /tmp/capture.pcap
# Скопировать локально:
scp server:/tmp/capture.pcap .
# Открыть:
wireshark capture.pcap
В Wireshark вы видите:
- Список пакетов — каждый с timestamp, source, destination, protocol, info.
- Детали выбранного пакета — разбор по слоям (Ethernet, IP, TCP, application).
- Hex dump — сырые байты.
- Фильтры в верхней панели.
Wireshark display filters
Фильтры Wireshark отличаются от tcpdump (BPF). Богаче, поддерживают application protocols.
# По адресу:
ip.addr == 10.0.0.42
ip.src == 10.0.0.42
ip.dst == 142.250.74.110
# По порту:
tcp.port == 443
tcp.dstport == 80
# По протоколу:
http
dns
tls
icmp
arp
# По содержимому HTTP:
http.request.method == "POST"
http.response.code == 500
http.host == "api.example.com"
http.user_agent contains "curl"
# По содержимому DNS:
dns.qry.name == "google.com"
dns.flags.response == 1
# TLS handshake типы:
tls.handshake.type == 1 # Client Hello
tls.handshake.type == 2 # Server Hello
# Комбинации:
ip.addr == 10.0.0.42 and tcp.port == 443
http.request.method == "POST" and http.host contains "api"
После применения фильтра — список пакетов сужается. Очень удобно искать конкретные события (например, все DNS-запросы на bank.com или все HTTP 5xx).
Follow TCP Stream — собрать поток
Один из самых полезных features Wireshark — Follow > TCP Stream (правый клик на пакете). Это покажет весь обмен данными между двумя сторонами как контигуальный текст, как будто вы смотрите на чат.
Для plain-text HTTP это будет:
GET /api/users HTTP/1.1
Host: api.example.com
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 123
{"users": [...]}
Сразу видно: вы запросили, сервер ответил. Это аналог curl -v, но «после факта», для уже прошедших запросов.
Для TLS-трафика — увы, только зашифрованные байты. Если у вас есть session keys (например, через SSLKEYLOGFILE env-переменную в браузере), Wireshark может расшифровать — но это редкий сценарий.
TLS-трафик — что видно
Даже без расшифровки TLS Wireshark показывает много полезного:
TLS Client Hello (тип 1):
SNI: api.example.com # !!! Открытый текст, виден всем
Versions: TLS 1.2, TLS 1.3
Cipher Suites: TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, ...
ALPN: h2, http/1.1
TLS Server Hello (тип 2):
Version: TLS 1.3
Cipher: TLS_AES_128_GCM_SHA256
ALPN: h2
TLS Certificate (тип 11):
Subject: CN=*.example.com
Issuer: CN=Let's Encrypt R3
Valid until: 2026-08-15
Это очень полезно для troubleshooting TLS:
- Wrong cert. Видно subject — сразу понятно, на правильный ли домен.
- Old TLS version. Видны versions — если только TLS 1.0, надо обновлять.
- No ALPN. HTTP/2 не работает потому что ALPN не negotiated.
- Cipher mismatch. Клиент предлагает только AEAD ciphers, сервер только non-AEAD — handshake failed.
Capture filters vs Display filters
Важно понимать разницу:
- Capture filters (tcpdump, или Wireshark на capture): применяются ДО записи. Только matching пакеты пишутся в pcap. Использует BPF-синтаксис (host, port, net, tcp/udp). Это уменьшает размер pcap.
- Display filters (Wireshark, не tcpdump): применяются ПОСЛЕ записи, для отображения. Можно фильтровать по чему угодно (HTTP-заголовкам, TLS-полям). Использует Wireshark-синтаксис (http.host, tls.handshake.type).
Стратегия:
# Захватываем с capture filter, чтобы файл был не миллионы пакетов:
sudo tcpdump -nn -i eth0 'host api.example.com' -w /tmp/api.pcap
# В Wireshark открываем и применяем display filter для precise search:
# Filter: http.response.code >= 400
Найти медленные запросы
В Wireshark есть встроенная аналитика — Statistics > Conversations показывает все TCP-соединения, время, объём, latency.
Через tcpdump можно тоже — но сложнее:
# Захват с timestamps:
sudo tcpdump -tttt -i eth0 'host api.example.com' -w /tmp/api.pcap
# Поиск самых медленных GET-ответов:
tcpdump -nn -r /tmp/api.pcap 'tcp[tcpflags] & tcp-push != 0' | head
# Wireshark:
# Statistics -> HTTP -> Requests
# или: tcp.analysis.flags == 1 # ретрансмиты
# или: tcp.analysis.duplicate_ack
Безопасность и приватность capture
tcpdump и Wireshark показывают сырой трафик. Если этот трафик содержит чувствительные данные (пароли в plain HTTP, токены в headers), они окажутся в pcap-файле и в любом, кто его получит.
Best practices:
- Не сохраняйте pcap-файлы с production-трафиком в shared storage.
- Удаляйте после анализа.
shred -u file.pcap. - Анонимизируйте перед отправкой support. Tools:
tcprewrite,tcpprep,pcap-rewrite. - Используйте capture filters.
not port 22(не захватывать вашу SSH-сессию — хотя она и зашифрована). - На corporate-серверах — только с разрешения security.
Анализ DNS в Wireshark
Wireshark — идеален для DNS-проблем:
# В фильтре:
dns
# Видно:
14:30:45.123 Standard query 0x1234 A google.com
14:30:45.156 Standard query response 0x1234 A google.com A 142.250.74.110
Дальше можно:
- Видеть, какие DNS-запросы делает ваше приложение.
- Считать latency DNS.
- Найти, какие имена не разрешаются (видны Server failure ответы).
- Видеть, какой именно resolver используется (по IP в IP-заголовке).
# Через tcpdump:
sudo tcpdump -nn -i any 'port 53' -A
# или для прицельного debug:
sudo tcpdump -nn -i any 'port 53 and udp' -w /tmp/dns.pcap
Попробуй сам
Серия экспериментов:
# 1. Захватить весь handshake одного HTTPS-запроса:
sudo tcpdump -nn -i any 'host api.github.com and port 443' -w /tmp/github.pcap &
sleep 1
curl https://api.github.com/users/torvalds
sleep 1
sudo killall tcpdump # остановить
# Прочитать:
tcpdump -nn -r /tmp/github.pcap | head -30
# Видим: DNS resolve, SYN, SYN-ACK, ACK, TLS Client Hello, Server Hello, ...
# 2. Захват DNS-резолва:
sudo tcpdump -nn -A -i any 'port 53' &
sleep 1
dig google.com
sleep 1
sudo killall tcpdump
# Видны DNS query и response в текстовом виде
# 3. Захват ARP (только в LAN):
sudo tcpdump -nn -i en0 arp
# В другом терминале:
ping 192.168.1.100 # пингуйте IP, которого нет в ARP-таблице
# Видно: ARP Request "Who has 192.168.1.100?"
# 4. Захват только SYN-пакетов (для детекции SYN flood или сканирования):
sudo tcpdump -nn -i any 'tcp[tcpflags] & tcp-syn != 0 and tcp[tcpflags] & tcp-ack = 0' -c 20
# Это все начала TCP-соединений
# 5. Захват для последующего Wireshark:
sudo tcpdump -nn -i any 'host github.com' -w /tmp/wireshark-test.pcap -G 10 # 10 секунд
# Скачайте Wireshark и откройте файл:
# brew install --cask wireshark # на macOS
# wireshark /tmp/wireshark-test.pcap
Из Wireshark поэкспериментируйте с display filters:
# В фильтр-баре:
http.request.method == "GET"
http.response.code >= 400
tls.handshake.type == 1
dns.qry.name contains "google"
tcp.analysis.retransmission
tcp.flags.syn == 1 and tcp.flags.ack == 0
Используйте Statistics меню для built-in analytics: conversations, endpoints, HTTP stats.
tcpdump BPF-фильтры: precision capture без 50GB pcap-файлов