
Tracer IPC Linux basato su BPF per pipe, segnali, socket Unix, loopback e pseudoterminali con cattura di metadati e contenuti, filtraggio e output JSON.
ipcdump è uno strumento per tracciare la comunicazione tra processi (IPC) su Linux. Copre la maggior parte dei meccanismi IPC comuni -- pipe, fifo, segnali, socket unix, networking basato su loopback e pseudoterminali. È uno strumento utile per eseguire il debug di applicazioni multiprocesso, ed è anche un modo semplice per capire come le diverse parti mobili del tuo sistema comunicano tra loro. ipcdump può tracciare sia i metadati che i contenuti di questa comunicazione, ed è particolarmente adatto per tracciare IPC tra processi di breve durata, che possono essere difficili da analizzare con strumenti di debug tradizionali, come strace o gdb. Ha anche alcune capacità di filtraggio di base per aiutarti a selezionare grandi quantità di eventi. La maggior parte delle informazioni che ipcdump raccoglie proviene da hook BPF posizionati su kprobe e tracepoint in funzioni chiave del kernel, anche se riempie anche alcune registrazioni dal filesystem /proc. A questo scopo ipcdump fa un uso intensivo di gobpf, che fornisce binding golang per il framework bcc.
| Ubuntu 18.04 LTS | Ubuntu 20.04 LTS | |
|---|---|---|
| 4.15.0 | Testato | Non testato |
| 5.4.0 | Non testato | Testato |
| 5.8.0 | Non testato | Testato* |
*Richiede la compilazione di bcc dal sorgente.
snap install go --classic
oppure direttamente dal sito web di 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).
Esegui come 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 è composto da una serie di collettori, ognuno dei quali è responsabile di un particolare tipo di evento IPC. Ad esempio, IPC_EVENT_LOOPBACK_SOCK_UDP o IPC_EVENT_SIGNAL.
In pratica, tutti i collettori sono costruiti utilizzando hook bpf attaccati a kprobe e tracepoint. Le loro implementazioni sono comunque completamente separate -- non c'è un motivo particolare per presumere che le nostre informazioni provengano sempre da bpf. Detto questo, i diversi collettori devono condividere un singolo modulo bpf, perché c'è del codice comune che devono condividere. A questo scopo, condividiamo un singolo BpfBuilder (che è essenzialmente un wrapper attorno alla concatenazione di stringhe di codice bcc) e ogni collettore registra il proprio codice con quel builder. L'intero script bcc viene poi caricato con gobpf, e ogni modulo posiziona gli hook di cui ha bisogno.
Attualmente ci sono due tipi di registrazioni contabili condivise tra i collettori IPC:
SocketIdentifier (internal/collection/sock_id.go) -- mappa tra struct sock* del kernel e i processi che li utilizzano.CommIdentifier (internal/collection/comm_id.go) -- mappa tra numeri pid e il nome del processo corrispondente (/proc/<pid>/comm).La contabilità fatta in ciascuno di questi è particolarmente importante per i processi di breve durata; mentre queste informazioni possono essere compilate successivamente in spazio utente analizzando /proc, spesso il processo rilevante sarà scomparso quando l'evento raggiunge il gestore. Detto questo, a volte inseriamo informazioni da /proc. Questo accade principalmente per processi che esistevano prima che ipcdump fosse eseguito; in questo caso non cattureremo eventi come la denominazione dei processi. SocketIdentifier e CommIdentifier cercano in qualche modo di astrarre questa dualità tra codice bcc e analisi di /proc dietro una singola API, anche se non è super-pulito. A proposito, nelle versioni super-nuove di Linux (5.8), gli iteratori bpf possono sostituire completamente questa contabilità, anche se per retrocompatibilità probabilmente dovremmo attenerci al paradigma hook-e-procfs per ora.
L'output degli eventi è realizzato attraverso la funzione comune EmitIpcEvent(), che prende un formato evento standard (processo sorgente, processo destinazione, coppie chiave-valore di metadati e contenuti) e lo produce in un formato unificato. Per risparmiare larghezza di banda degli eventi, i collettori di solito non producono i contenuti IPC se il flag -x non è specificato. Questo viene fatto con un po' di magia di preelaborazione in internal/collection/ipc_bytes.go.
Per favore fallo! Dai un'occhiata a TODO per le cose veramente importanti. La maggior parte del lavoro iniziale su ipcdump probabilmente coinvolgerà la realizzazione di adattamenti per diverse versioni e simboli del kernel.