
BPF 기반 Linux IPC 추적기로서 파이프, 시그널, 유닉스 소켓, 루프백 및 의사 터미널에 대한 메타데이터 및 콘텐츠 캡처, 필터링, JSON 출력을 지원합니다.
ipcdump는 Linux에서 프로세스 간 통신(IPC)을 추적하기 위한 도구입니다. 파이프, FIFO, 시그널, 유닉스 소켓, 루프백 기반 네트워킹, 가상 터미널과 같은 대부분의 일반적인 IPC 메커니즘을 다룹니다. 멀티 프로세스 애플리케이션 디버깅에 유용한 도구이며, 시스템의 다양한 구성 요소가 서로 어떻게 통신하는지 이해하는 간단한 방법이기도 합니다. ipcdump는 이 통신의 메타데이터와 내용을 모두 추적할 수 있으며, 특히 strace나 gdb와 같은 전통적인 디버깅 도구를 사용하기 어려운 짧은 수명의 프로세스 간 IPC를 추적하는 데 적합합니다. 또한 대량의 이벤트를 선별하는 데 도움이 되는 몇 가지 기본 필터링 기능도 있습니다. ipcdump가 수집하는 정보의 대부분은 커널의 주요 함수에 있는 kprobe와 tracepoint에 배치된 BPF 훅에서 비롯되지만, /proc 파일 시스템에서 일부 부기(bookkeeping) 정보도 채웁니다. 이를 위해 ipcdump는 bcc 프레임워크를 위한 golang 바인딩을 제공하는 gobpf를 많이 사용합니다.
| 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
이벤트당 덤프할 최대 바이트 수, 또는 완전한 이벤트의 경우 0 (클 수 있음). -x가 지정된 경우에만 의미 있음.
-D value
대상 커맨드(comm)로 필터링 (여러 번 지정 가능)
-L 손실된 이벤트 정보를 출력하지 않음
-P value
커맨드(comm)로 필터링 (소스 또는 대상, 여러 번 지정 가능)
-S value
소스 커맨드(comm)로 필터링 (여러 번 지정 가능)
-c uint
<count>개의 이벤트 후 종료
-d value
대상 PID로 필터링 (여러 번 지정 가능)
-f string
<text|json> 출력 형식 (기본값은 text) (기본값 "text")
-p value
PID로 필터링 (소스 또는 대상, 여러 번 지정 가능)
-s value
소스 PID로 필터링 (여러 번 지정 가능)
-t value
유형별로 필터링 (여러 번 지정 가능).
가능한 값: 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 해당되는 경우 IPC 바이트 덤프 (이벤트 세부 정보만이 아님)
root로 실행:
# 시스템의 모든 IPC 덤프
./ipcdump
# 두 프로세스 간 전송되는 시그널 덤프
./ipcdump -t kill
# PID 1337로/로부터의 루프백 TCP 연결 메타데이터 덤프
./ipcdump -t loopback-tcp -p 1337
# Xorg로부터의 유닉스 소켓 IPC 메타데이터 및 내용 덤프
./ipcdump -t unix -x -S Xorg
# JSON 형식의 파이프 I/O 메타데이터 및 내용의 처음 64바이트 덤프
./ipcdump -t pipe -x -B 64 -f json
ipcdump는 각각 특정 유형의 IPC 이벤트를 담당하는 일련의 수집기(collector)로 구성됩니다. 예를 들어, IPC_EVENT_LOOPBACK_SOCK_UDP 또는 IPC_EVENT_SIGNAL이 있습니다.
실제로 모든 수집기는 kprobe와 tracepoint에 연결된 bpf 훅을 사용하여 구축됩니다. 그러나 구현은 완전히 분리되어 있습니다. 정보가 항상 bpf에서 올 것이라고 가정할 특별한 이유는 없습니다. 하지만 서로 다른 수집기는 공유해야 하는 공통 코드가 있기 때문에 단일 bpf 모듈을 공유해야 합니다. 이를 위해 단일 BpfBuilder(본질적으로 bcc 코드 문자열을 연결하는 래퍼)를 공유하고 각 수집기는 자체 코드를 해당 빌더에 등록합니다. 그런 다음 전체 bcc 스크립트가 gobpf와 함께 로드되고 각 모듈은 필요한 훅을 배치합니다.
현재 IPC 수집기 간에 공유되는 두 가지 종류의 부기(bookkeeping)가 있습니다:
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 반복자(iterator)가 이 부기를 완전히 대체할 수 있지만, 이전 버전과의 호환성을 위해 지금은 훅과 procfs 패러다임을 고수해야 할 것입니다.이벤트 출력은 공통 EmitIpcEvent() 함수를 통해 수행되며, 이 함수는 표준 이벤트 형식(소스 프로세스, 대상 프로세스, 메타데이터 키-값 쌍, 내용)을 가져와 통합된 형식으로 출력합니다. 이벤트 대역폭을 절약하기 위해 -x 플래그가 지정되지 않은 경우 수집기는 일반적으로 IPC 내용을 출력하지 않습니다. 이는 internal/collection/ipc_bytes.go의 멋진 전처리 마법을 통해 수행됩니다.
부탁드립니다! 정말 중요한 내용은 TODO를 확인하세요. ipcdump의 초기 작업 대부분은 다양한 커널 버전과 심볼에 대한 조정을 포함할 것입니다.