Захват трафика с помощью tcpdump и анализ на java

crocodile

Мотивация

Анализ TCP/IP трафика сетевого приложения весьма эффективный способ

  • Диагностировать сетевые проблемы, исключив влияние фреймворков, ОС, языка программирования и прочего.
  • Посчитать всякую разную аналитику
  • Написать честный мониторинг по принципу man-in-the-middle
  • В качестве архива писать для «истории»
  • Реверс существующего вражеского протокола, понимание что делает «чужое» приложение

Когда анализ трафика не поможет

  • для выяснения багов, т.к. лучше смотреть в код приложения — захват и анализ трафика гораздо сложнее
  • когда мало времени, процесс это творческий и трудозатратный т.к. вылезают разные мелкие проблемы

Подходы

  1. «На лету» — поймали и сразу смотрим, в крайнем случае сохраняем (небольшие объемы) — для этого отлично подходит Wireshark
  2. «Запишем сейчас, разберемся потом» — этот вариант лучше годится когда поток данных большой или нам надо анализировать dump-ы программно

Случай №1 хорошо описан на Хабре и не раз

Вся эта статья только про случай №2.

Подоготовительная стадия

OS & права

Желательно иметь linux с ядром >= 2.6.

Надо получить либо root либо sudo права на сам tcpdump если мы планируем ловить всё что идет по проводу (promisc. mode).

Если OS==Ubuntu надо так же вырубить app armor.

На windows тоже есть порты tcpdump, но всё хуже. Например разрешение таймера грубее и нельзя ловить общение по localhost.  Для ловли по localhost лучше всего использовать не tcpdump и не Wireshark, а RawCap вот так: RawCap.exe -f 127.0.0.1 dumpfile.pcap. Чудо утилита весит 23Kb.

Потери пакетов

При захвате трафика если наш хост не успевает перехватывать все пакеты — у нас будут заметные потери пакетов.

Поэтому крайне важно выкручивать все буферы и снижать время захвата 1 пакета. Об этом рекомендации ниже.

TCP/IP buffers

Если у нас большой поток данных желательно подкрутить вот эти буферы

sysctl -w net.core.netdev_max_backlog=250000
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.rmem_default=16777216

Latency

Важно определиться какое влияние на latency нас устроит. Либо надо разгрузить & ускорить захват трафика по максимуму либо использовать port mirroring на умном свитче.

Port mirroring

Если решение не должно вносить задержек на боевой хост — лучше настроить switch так чтобы он дублировал все пакеты на нужный нам хост на отдельный интерфейс, и на этот интерфейс мы повесим выделенный хост исключительно для захвата трафика.

Hardware TCP/IP

Далее если мы хотим очень точно мерить время прихода пакета, то ОС должна вносить минимум задержек. Желательно иметь аппаратный TCP/IP на сетевой карте (например от Mellanox за 1000$).

Толщина канала

Если трафика много, например не 100mit, а 1Gbit или даже 10Gbit, то позможно понадобится поставить хороший производительный RAID-0 на машину которая будет все записывать

Hardware Network TAP

В экстремальных случаях вместо tcpdump можно взять полностью железное решение по захвату ethernet-трафика

Высокая точность часов

Нам может нехватать точности системных часов чтобы отличать пакеты, поэтому важно чтобы системный таймер в ОС тикал максимально быстро. На некоторых ОС разрешение таймера неудовлетворительное.

load average самого CPU должен быть очень низким чтобы переключение контекста не сбивало таймер.

Захват трафика

Вначале надо раздобыть tcpdump, и ознакомиться с мануалом на tcpdump.org

На этом этапе нам надо понять

  • какой протокол мы ловим — что-то поверх TCP или UDP или что-то ниже уровнем
  • знать порты: host1:port1 -> host2:port2

и составить фильтр пакетов — это такое выражение которое из интерфейса будет отфильтровывать только нужные нам пакеты.

Пример

tcpdump -i eth0 ‘ tcp and (dst 10.230.6.245 or src 10.230.6.245) ‘
 -n -nn -K -s 50000 -C 100 -B 400000 -w mydump

поясню важные параметры
-K — не проверять контрольную сумму пакетов, если мы ловим в promisc. mode то мы берем пакет у сетевой карты до того как она успевает проставить контрольную сумму пакета, соответсвенно все пакеты будут генерировать warning что контрольная сумма не валидна (хотя на деле все ок)
-n — не определять dns имя по ip (снижает производительность)
-nn — не определять имена портов (снижает производительность)
-s 50000 — максимальный размер пакета (если пакеты маленькие то для улучшения прозводительности можно ограничить размер)
-С 100 — нарезать файлами по 100мб, это полезно чтобы иметь возможность открывать часть пакетов в Wireshark или скачивать за разумное время
-G 3600 — новый файл каждый час (на всякий случай)
-w mycap — пишем в файлы вида mycap.xxxx.pcap
-w ‘dump_(%Y%m%d%H%M%S%z).pcap’ — пример форматирования даты старта в имя файла см. формат
-i eth0 — ловим все ethernet пакеты но только с интерфейса, eth0 требует root
-i any — ловим со всех интерфесов, на уровне ОС
‘ tcp and (dst 10.230.6.245 or src 10.230.6.245) ‘ — наш фильтр, отлавливает только TCP пакеты источником или получателем которых является хост 245.

Про фильтры детально можно почитать вот здесь:
Фильтры захвата для сетевых анализаторов
Мониторинг сети с помощью tcpdump
tcpdump examples
tcpdump manual

Парсер трафика

C помощью Jnetpcap можно парсить pcap-файлы прямо из java.
PcapPacket содержит заголовки: Meta headers / Capture header / Ip header / Tcp header / Payload.

public class A {
    public static void main(String[] args) {
        Pcap pcap = Pcap.openOffline(file, errbuf);
        PcapPacketHandler<String> jpacketHandler = new PcapPacketHandler<String>() {
            public void nextPacket(PcapPacket packet, String user) {
                System.out.printf("Received at %s caplen=%-4d len=%-4d %s\n",
                    new Date(packet.getCaptureHeader().timestampInMillis()),
                    packet.getCaptureHeader().caplen(), // Length actually captured
                    packet.getCaptureHeader().wirelen(), // Original length
                    user // User supplied object
                    );
            }
        };
        pcap.loop(10, jpacketHandler, "jNetPcap rocks!");
    }
}

К сожалению, тут есть некоторые грабли

  • TCP пакеты могут теряться/переупорядочиваться/фрагметироваться. Если это локальная сеть то будет 0.01% фрагметированных пакетов и в этом случае пакеты можно просто склеивать и это будет работать. Иначе надо писать руками склейку TCP пакетов с учетом tcp sequence number что гораздо сложнее. Есть утилиты которые могут выделять в pcap файле tcp-потоки данных, но их тяжело интегрировать в код. Такое умеет Wireshark и tcptrace.
  • библиотека пользует нативную pcap.so которую иногда надо будет собрать самому, все другие библиотеки которые не используют JNI — не умеют хорошо парсить все особенности pcap формата.
  • библиотека активно пишет в offheap-память, и работает нестабильно.
  • чтобы ходить по набору из 50+ pcap файлов, придется написать собственный велосипед т.к. за раз хорошо влезает в память только 1 файл
  • вот с такими параметрами удалось ее запустить и получить 20мб\с разбора файлов в один поток
-D64 -Djava.library.path=path-to-so-lib -Xmx500m -Xms500m
-XX:MaxDirectMemorySize=2000M -Dnio.ms=1000mb -Dnio.mx=2000mb

Ссылки

Инструменты
Wireshark — захват, просмотр, фильтрация трафика, хорошо работает только с небольшими файлами. Введение на Хабре, фильтры для захвата трафика, фильтры для отображения в UI
mergecap — утилита для склеивания pcap-файлов
tcptrace — утилита для сборки tcp-stream из pcap файлов.
HexWorkshop — серьезный hex-редактор, просмотр структур данных которые можно определять на си-подобном языке, бинарный diff, итд
RawCap — перехват всего трафика на определенном интерфейсе  в т.ч. и loopback (win-only)

Tcpdump
Фильтры захвата для сетевых анализаторов
Мониторинг сети с помощью tcpdump
tcpdump examples
tcpdump manual

Java API
Jnetpcap java library
Netutils java library

Traffic
Packet capture in 10gbit environments
Introduction to network latency engineering
Mellanox low latency benchmark report (2mks host to host)

Tcp tuning on linux
Tcp retransmits
TCP/IP illustrated (book)

Другие записи...

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

* Please Enter the Output

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>