
Трассировщик IPC Linux на основе BPF для каналов (pipes), сигналов, сокетов Unix, loopback и псевдотерминалов с захватом метаданных и содержимого, фильтрацией и выводом в JSON.
ipcdump — это инструмент для трассировки межпроцессного взаимодействия (IPC) в Linux. Он охватывает большинство распространённых механизмов IPC: каналы (pipes), именованные каналы (fifos), сигналы, сокеты Unix, сетевое взаимодействие через loopback и псевдотерминалы. Это полезный инструмент для отладки многопроцессных приложений, а также простой способ понять, как разные движущиеся части вашей системы взаимодействуют друг с другом. ipcdump может трассировать как метаданные, так и содержимое этого общения, и особенно хорошо подходит для трассировки IPC между короткоживущими процессами, что может быть сложно с помощью традиционных средств отладки, таких как strace или gdb. Он также имеет базовые возможности фильтрации, чтобы помочь вам разобраться в большом количестве событий. Большая часть информации, которую собирает ipcdump, поступает из BPF-хуков, установленных на kprobes и tracepoints в ключевых функциях ядра, хотя он также заполняет некоторые вспомогательные данные из файловой системы /proc. Для этого ipcdump активно использует gobpf, который предоставляет привязки Go для фреймворка bcc.
| Ubuntu 18.04 LTS | Ubuntu 20.04 LTS | |
|---|---|---|
| 4.15.0 | Протестировано | Не тестировалось |
| 5.4.0 | Не тестировалось | Протестировано |
| 5.8.0 | Не тестировалось | Протестировано* |
*Требуется сборка bcc из исходников
snap install go --classic
или напрямую с сайта golang
git clone https://github.com/guardicore/IPCDump
cd IPCDump/cmd/ipcdump
go build
./ipcdump -h
Usage of ./ipcdump:
-B uint
max number of bytes to dump per event, or 0 for complete event (may be large). meaningful only if -x is specified.
-D value
filter by destination comm (can be specified more than once)
-L do not output lost event information
-P value
filter by comm (either source or destination, can be specified more than once)
-S value
filter by source comm (can be specified more than once)
-c uint
exit after <count> events
-d value
filter by destination pid (can be specified more than once)
-f string
<text|json> output format (default is text) (default "text")
-p value
filter by pid (either source or destination, can be specified more than once)
-s value
filter by source pid (can be specified more than once)
-t value
filter by type (can be specified more than once).
possible values: a|all k|signal u|unix ud|unix-dgram us|unix-stream t|pty lo|loopback lt|loopback-tcp lu|loopback-udp p|pipe
-x dump IPC bytes where relevant (rather than just event details).
Запускать от root:
# dump all ipc on the system
./ipcdump
# dump signals sent between any two processes
./ipcdump -t kill
# dump loopback TCP connection metadata to or from pid 1337
./ipcdump -t loopback-tcp -p 1337
# dump unix socket IPC metadata and contents from Xorg
./ipcdump -t unix -x -S Xorg
# dump json-formatted pipe i/o metadata and first 64 bytes of contents
./ipcdump -t pipe -x -B 64 -f json
ipcdump состоит из набора сборщиков (collectors), каждый из которых отвечает за определённый тип IPC-события. Например, IPC_EVENT_LOOPBACK_SOCK_UDP или IPC_EVENT_SIGNAL.
На практике все сборщики построены с использованием BPF-хуков, прикреплённых к kprobes и tracepoints. Их реализации полностью независимы — нет особых причин полагать, что наша информация всегда будет поступать из BPF. Тем не менее, разные сборщики должны использовать один модуль BPF, потому что им нужно разделять некоторый общий код. Для этого мы используем единый BpfBuilder (по сути, обёртку вокруг конкатенации строк кода bcc), и каждый сборщик регистрирует свой собственный код в этом построителе. Полный скрипт bcc затем загружается с помощью gobpf, и каждый модуль размещает необходимые хуки.
В настоящее время существует два вида учётных данных, общих для всех сборщиков IPC:
SocketIdentifier (internal/collection/sock_id.go) — сопоставляет между struct sock* ядра и использующими их процессами.CommIdentifier (internal/collection/comm_id.go) — сопоставляет номера PID с соответствующими именами процессов (/proc/<pid>/comm).
Учётные данные, выполняемые в каждом из них, особенно важны для короткоживущих процессов; хотя эту информацию можно заполнить позже в пользовательском режиме, парся /proc, часто соответствующий процесс исчезает к моменту обработки события. Тем не менее, мы иногда заполняем информацию из /proc. Это происходит в основном для процессов, которые существовали до запуска ipcdump; в таком случае мы не перехватываем события, например, именования процессов. SocketIdentifier и CommIdentifier пытаются абстрагировать эту двойственность между кодом bcc и парсингом /proc за единым API, хотя это не очень чисто. Кстати, в сверхновых версиях Linux (5.8) BPF-итераторы могут полностью заменить эту учётную запись, хотя для обратной совместимости, вероятно, стоит пока придерживаться парадигмы хуки+procfs.Вывод событий осуществляется через общую функцию EmitIpcEvent(), которая принимает стандартный формат события (процесс-источник, процесс-назначение, пары ключ-значение метаданных и содержимое) и выводит его в едином формате. Чтобы сэкономить полосу пропускания событий, сборщики обычно не выводят содержимое IPC, если не указан флаг -x. Это делается с помощью некоторой хитроумной предварительной обработки в internal/collection/ipc_bytes.go.
Пожалуйста, участвуйте! Посмотрите TODO для действительно важных задач. Большая часть ранней работы над ipcdump, вероятно, будет связана с внесением корректировок для разных версий ядра и символов.