Методология захвата данных: Работа с интерфейсами и синтаксис фильтров захвата в tcpdump
Методология захвата данных: Работа с интерфейсами и синтаксис фильтров захвата в tcpdump
Представьте, что вы подключились к магистральному маршрутизатору с интерфейсом 10 Гбит/с, чтобы отловить специфичную аномалию в TCP-рукопожатиях, возникающую раз в несколько минут. Если вы просто запустите команду захвата всего проходящего трафика с записью в файл, вы будете сохранять на диск более гигабайта данных каждую секунду. Менее чем через минуту сервер либо исчерпает свободное место, либо «захлебнётся» от нехватки производительности подсистемы ввода-вывода (I/O), так и не решив исходную задачу. Искусство сетевого анализа начинается не с умения читать дампы в Wireshark, а с хирургически точного захвата исключительно тех байтов, которые имеют значение для расследования.
Сетевые интерфейсы и барьер аппаратной фильтрации
Сетевая карта (NIC) сервера по умолчанию работает как строгий фильтр. Кадры, летящие по физической среде (медному кабелю или оптике), достигают порта, после чего контроллер проверяет MAC-адрес назначения. Если MAC-адрес в заголовке кадра не совпадает с аппаратным адресом самой сетевой карты и не является широковещательным (broadcast), контроллер молча отбрасывает этот кадр. Центральный процессор сервера и операционная система даже не узнают о существовании этого пакета.
Для анализа транзитного трафика, который проходит через коммутатор (например, при использовании SPAN-порта) или при прослушивании среды с разделяемой средой передачи, такое поведение неприемлемо. Анализатору нужно видеть всё.
Здесь в игру вступает Promiscuous mode (неразборчивый режим). При запуске утилиты захвата, такой как tcpdump, она отправляет ядру ОС запрос на перевод указанного сетевого интерфейса в этот режим. В promiscuous mode аппаратный фильтр MAC-адресов отключается, и сетевая карта начинает передавать в операционную систему копии абсолютно всех кадров, достигающих физического порта.
В Linux-системах утилита tcpdump позволяет явно указывать интерфейс для прослушивания с помощью флага -i.
tcpdump -i eth0— захват на конкретном физическом интерфейсе.tcpdump -i lo— захват на loopback-интерфейсе (локальный трафик внутри самого хоста, например, от локального сервиса к локальной базе данных).tcpdump -i any— специальный псевдо-интерфейс в Linux, который собирает трафик со всех активных интерфейсов системы. Важный нюанс: при захвате сanyиспользуется специальный тип канального заголовка (Linux cooked capture, SLL), что меняет структуру первых байтов пакета и может сломать фильтры, опирающиеся на жесткие смещения MAC-адресов.
Архитектура BPF: Фильтрация в пространстве ядра
Главная проблема высоконагруженных сетей — стоимость копирования данных. Когда пакет попадает в сетевую карту, он копируется в оперативную память, в пространство ядра (kernel space). Если программа-анализатор (например, tcpdump или Wireshark), работающая в пространстве пользователя (user space), захочет проанализировать пакет, ядру придётся скопировать этот пакет из своей памяти в память программы. Операция копирования (context switch и memory copy) требует процессорного времени. Если копировать миллионы пакетов в секунду, процессор будет занят только обслуживанием захвата.
Чтобы решить эту проблему, в 1992 году была разработана архитектура BPF (Berkeley Packet Filter).
Идея BPF гениальна в своей простоте: вместо того чтобы копировать все пакеты в user space и позволять программе решать, нужны они ей или нет, программа компилирует правила фильтрации в специальный байт-код и загружает его прямо в ядро ОС. В ядре работает крошечная, невероятно быстрая виртуальная машина. Она применяет этот байт-код к каждому приходящему пакету до того, как он будет скопирован в пространство пользователя. Если пакет не проходит проверку BPF, он просто отбрасывается на уровне ядра, экономя колоссальные ресурсы.
Именно поэтому синтаксис фильтров в tcpdump (Capture Filters) и синтаксис фильтров в строке поиска Wireshark (Display Filters) кардинально различаются. Capture Filters транслируются в низкоуровневый код BPF для ядра, а Display Filters работают уже с захваченными данными в комфортном пространстве пользователя, где можно позволить себе сложные строковые сравнения и сборку фрагментированных сессий.
Синтаксис примитивов: Построение фильтров захвата
Синтаксис BPF-фильтров строится из примитивов, которые состоят из идентификатора (имени или числа) и предшествующих ему квалификаторов. Квалификаторы делятся на три типа:
- Тип (Type): Указывает, к какой сущности относится идентификатор. Возможные значения:
host(узел),net(подсеть),port(порт),portrange(диапазон портов). Если тип не указан, по умолчанию подразумеваетсяhost. - Направление (Dir): Указывает направление потока. Возможные значения:
src(источник),dst(назначение),src or dst,src and dst. По умолчанию подразумеваетсяsrc or dst. - Протокол (Proto): Ограничивает проверку конкретным протоколом. Например:
ether,ip,ip6,arp,tcp,udp.
Комбинируя эти квалификаторы, мы создаем базовые условия. Рассмотрим несколько примеров:
dst host 192.168.1.50— захватить только те пакеты, где IP-адрес назначения равен 192.168.1.50.src net 10.0.0.0/8— захватить трафик, исходящий из подсети 10.0.0.0/8.tcp dst port 443— захватить только TCP-сегменты, направляющиеся на 443 порт.
Для создания сложных логических конструкций примитивы объединяются операторами:
- Конъюнкция:
andили&& - Дизъюнкция:
orили|| - Отрицание:
notили!
Рассмотрим практическую задачу. Нам нужно проанализировать веб-трафик (порты 80 и 443) к нашему серверу, но мы хотим исключить из дампа весь административный SSH-трафик (порт 22), который генерируют инженеры из подсети управления 10.5.5.0/24.
Команда будет выглядеть так:
tcpdump -i eth0 'tcp and (port 80 or port 443) and not (src net 10.5.5.0/24 and port 22)'
Обратите внимание на одинарные кавычки вокруг фильтра. Они критически важны при работе в терминале Linux, так как символы скобок () и амперсандов && интерпретируются командной оболочкой (bash/zsh) как управляющие символы. Кавычки заставляют оболочку передать строку в tcpdump в неизменном виде.
Хирургия на уровне байтов: Смещения и битовые маски
Базовые примитивы отлично справляются с IP-адресами и портами. Но что, если нам нужно заглянуть глубже? Например, поймать только пакеты установки соединения или пакеты определенного размера. Для этого BPF предоставляет механизм прямого доступа к памяти пакета по смещению (offset).
Синтаксис выглядит так: proto[offset:size].
proto— протокол, от начала заголовка которого мы считаем байты (например,ip,tcp,udp,icmp).offset— количество байтов от начала заголовка. Нумерация начинается с нуля.size— количество байтов для чтения (1, 2 или 4). Если не указано, читается 1 байт.
Самый классический пример использования смещений — фильтрация по флагам TCP. (Детальную структуру заголовка TCP и состояния сессий мы разберем в отдельной главе, сейчас нас интересует механика работы с байтами).
Флаги TCP находятся в 13-м байте (смещение 13) от начала TCP-заголовка. Этот байт содержит 8 бит, 6 из которых отвечают за основные флаги:
- Бит 5: URG (значение )
- Бит 4: ACK (значение )
- Бит 3: PSH (значение )
- Бит 2: RST (значение )
- Бит 1: SYN (значение )
- Бит 0: FIN (значение )
Если пакет представляет собой запрос на установку соединения (только флаг SYN), значение 13-го байта в десятичной системе будет равно . Фильтр tcp[13] == 2 поймает чистые SYN-пакеты.
Однако в реальной сети пакет может нести несколько флагов одновременно. Например, ответ сервера (SYN-ACK) содержит установленные флаги SYN () и ACK (). Значение байта будет . Фильтр tcp[13] == 2 проигнорирует такой пакет.
Чтобы проверить, установлен ли конкретный бит независимо от состояния других битов, применяется побитовая операция И (bitwise AND, обозначается как &). Логика операции такова: мы накладываем «маску» на проверяемый байт. Если бит в маске равен 1, мы смотрим на соответствующий бит в байте. Если бит в маске равен 0, мы его игнорируем.
Маска для флага SYN равна (в двоичном виде ). Проверим пакет с флагами SYN-ACK (значение , или ):
Результат равен .
Проверим пакет только с флагом ACK (значение , или ):
Результат равен .
Следовательно, универсальный фильтр для захвата абсолютно всех пакетов, в которых присутствует флаг SYN (будь то чистый SYN или SYN-ACK), выглядит так:
tcpdump -i eth0 'tcp[13] & 2 != 0'
Этот подход применим к любому протоколу. Например, тип ICMP-сообщения хранится в самом первом байте заголовка ICMP (смещение 0). Эхо-запрос (ping) имеет тип . Фильтр icmp[0] == 8 оставит в дампе только запросы ping, отбросив ответы и сообщения об ошибках маршрутизации.
Управление процессом захвата: Снапшоты и кольцевые буферы
Даже при идеальной фильтрации BPF, запись полных пакетов (которые могут достигать 1500 байт в стандартном Ethernet) быстро расходует дисковое пространство. Если ваша задача — анализ сетевой маршрутизации или факта установки соединений, вам не нужно содержимое пакета (payload). Вам нужны только заголовки (Ethernet, IP, TCP/UDP).
Параметр snaplen (Snapshot Length), задаваемый флагом -s, указывает tcpdump, сколько байт от начала каждого пакета нужно сохранить.
Команда tcpdump -s 96 -w headers.pcap обрежет каждый пакет до 96 байт. Этого с запасом хватит, чтобы вместить заголовки L2, L3 и L4, но при этом размер итогового файла дампа уменьшится в десятки раз по сравнению с сохранением полных пакетов. Значение -s 0 в современных версиях утилиты означает захват пакета целиком.
Для долгосрочного мониторинга используется механизм кольцевых буферов. Вместо записи в один бесконечно растущий файл, tcpdump может разбивать дамп на части и перезаписывать старые файлы по кругу.
- Флаг
-C(заглавная C) задает максимальный размер одного файла в мегабайтах. - Флаг
-Wзадает максимальное количество файлов.
tcpdump -i eth0 -w capture.pcap -C 100 -W 5
Эта команда создаст файлы capture.pcap0, capture.pcap1 и так далее. Как только размер текущего файла достигнет 100 МБ, начнется запись в следующий. Когда будет записано 5 файлов (суммарно 500 МБ), tcpdump вернется к первому файлу и перезапишет его. Это гарантирует, что захват никогда не переполнит диск сервера, при этом у вас всегда будет доступ к последним 500 МБ трафика.
Понимание механизмов работы интерфейсов, архитектуры BPF и битовой математики — это фундамент. Инструменты вроде tcpdump лишь предоставляют интерфейс к этим механизмам. Логика побитовых масок и смещений, которую мы рассмотрели на примере TCP-флагов, лежит в основе написания высокопроизводительных правил для межсетевых экранов и создания первых сигнатур для систем глубокого анализа трафика (DPI), к которым мы перейдем на следующих этапах.