
Un moderno tracer di syscall costruito su eBPF. Pensa a strace, ma con una vera TUI, filtri intelligenti, decrittazione TLS e output che sia effettivamente leggibile.
Un tracciatore di syscall per Linux, basato su eBPF. Come strace ma con una TUI live, filtri intelligenti e decodifica degli argomenti che puoi leggere davvero.

$ sudo snoop curl https://example.com
[ 0.001] curl(1234/1234) openat(AT_FDCWD, "/etc/ssl/certs/ca-certificates.crt", O_RDONLY) = 4 <0.031ms>
[ 0.002] curl(1234/1234) read(4, 0x7f3a1c000b20, 4096) = 4096 <0.012ms>
[ 0.003] curl(1234/1234) socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 5 <0.008ms>
[ 0.004] curl(1234/1234) connect(5, 93.184.216.34:443) = 0 <42.187ms>
[ 0.046] curl(1234/1234) sendto(5, 0x55a3bc001b40, 78, MSG_NOSIGNAL) = 78 <0.011ms>
Oppure eseguilo senza --raw e ottieni una TUI a schermo intero:
snoop pid:1234 comm:curl events:142 elapsed:0.341s
┌── syscall stream ─────────────────────────────────────┐┌── top syscalls ─────────┐
│ [ 0.001] curl openat("/etc/ssl/…") = 4 <0.031ms> ││ syscall count pct│
│ [ 0.002] curl read(4, …) = 4096 ││ read 38 26.8%│
│ [ 0.003] curl socket(AF_INET, …) = 5 ││ write 21 14.8%│
│ [ 0.004] curl connect(5, 93.184.216.34:443) = 0 ││ openat 18 12.7%│
│ [ 0.046] curl sendto(5, …) = 78 ││ mmap 14 9.9%│
└───────────────────────────────────────────────────────┘└─────────────────────────┘
[q]uit [Space]pause [/]search [f]iles [n]et [c]lear [↑↓]scroll [G]bottom
strace usa ptrace, che ferma il tuo processo ad ogni syscall. snoop usa invece tracepoint eBPF: il tuo processo continua a girare a piena velocità mentre il tracciamento avviene nel kernel. Oltre alle prestazioni, snoop decodifica gli argomenti in qualcosa di leggibile, ha una TUI in tempo reale e può salvare, riprodurre e comparare tracce.
--raw (compatibile con strace), --json (JSON Lines per jq), --explain (raggruppa le syscall in riassunti di attività ad alto livello)--files, --net, --slow 10, --syscall openat-p PID) o avviane uno (snoop <cmd>)--follow traccia anche i figli creati con fork--docker <nome> e tracciano tutto dentro un contenitoreNiente moduli kernel, niente toolchain C. I programmi eBPF sono puri Rust (aya) e sono incorporati nel binario.
CAP_BPF + CAP_PERFMONcurl -L https://github.com/pandaadir05/snoop/releases/latest/download/snoop-x86_64-linux.tar.gz \
| tar -xz
sudo install -m755 snoop /usr/local/bin/snoop
Per aarch64, sostituisci x86_64 con aarch64.
cargo install --git https://github.com/pandaadir05/snoop snoop
Questo compila automaticamente i programmi eBPF. Nessuna toolchain C o header del kernel necessari, solo Rust.
# Traccia un comando
sudo snoop ls /etc
sudo snoop -- nginx -g 'daemon off;'
# Attaccati a un processo in esecuzione
sudo snoop -p $(pidof postgres)
sudo snoop -p 1234 --follow # traccia anche i figli forkati
# Contenitori
sudo snoop --docker my-nginx
sudo snoop --pod my-app-pod --namespace production
# Filtraggio
sudo snoop -p 1234 --files # solo chiamate al filesystem
sudo snoop -p 1234 --net # solo chiamate di rete
sudo snoop -p 1234 --slow 5 # solo chiamate più lente di 5ms
sudo snoop -p 1234 --syscall openat --syscall read
--explain raggruppa le syscall raw in riassunti di alto livello invece di mostrare ogni chiamata singolarmente:
sudo snoop -p 1234 --explain
READ /etc/passwd ↓1.2 KB (2 chiamate, 0.80ms)
NET 127.0.0.1:5432 ↑512 B ↓4.0 KB (18.20ms)
EXEC /usr/bin/python3
Aggancia SSL_write/SSL_read in OpenSSL per catturare il testo in chiaro:
sudo snoop -p 1234 --tls
sudo snoop -p 1234 --ltrace
Registra una traccia, poi riproducila più tardi senza root:
sudo snoop record -p 1234 -o trace.snoop
snoop view trace.snoop
snoop view trace.snoop --files --slow 5 --json | jq 'select(.name=="read")'
Utile per individuare regressioni dopo un deploy:
sudo snoop record -p 1234 -o before.snoop
# ... deploy della modifica ...
sudo snoop record -p 1234 -o after.snoop
snoop diff before.snoop after.snoop
CONTEGGIO SYSALL
read 1200 → 1800 (+50.0%) ▲
openat 340 → 210 (-38.2%) ▼
REGRESSIONI DI DURATA (mediana)
read 0.02ms → 0.08ms (+300%)
SOLO IN after
statx (4x)
sudo snoop -p 1234 --json | jq 'select(.name == "connect")'
sudo snoop -p 1234 --flamegraph syscalls.svg
-p, --pid <PID> Attaccati a un processo in esecuzione
--follow Traccia i figli forkati (richiede --pid)
--docker <NOME|ID> Traccia tutti i processi in un contenitore Docker
--pod <POD> Traccia tutti i processi in un pod Kubernetes
-n, --namespace <NS> Namespace Kubernetes (default: default)
--raw Output su una riga compatibile con strace
--json JSON Lines — un oggetto per syscall
--explain Riepilogo semantico delle attività
--files Solo syscall del filesystem
--net Solo syscall di rete
--slow <MILLIS> Solo chiamate più lente della soglia
--syscall <NOME> Solo questa syscall (ripetibile)
--no-decode Argomenti in esadecimale raw, nessuna decodifica
--tls Cattura testo in chiaro TLS tramite uprobe SSL_write/SSL_read
--ltrace Traccia malloc/free/calloc/realloc
--flamegraph <PERCORSO> Scrivi SVG flamegraph all'uscita
--ebpf-obj <PERCORSO> Sovrascrivi l'oggetto eBPF incorporato [$SNOOP_EBPF_OBJ]
Due programmi eBPF si agganciano a raw_syscalls/sys_enter e sys_exit. All'ingresso, il numero di syscall e gli argomenti vengono inseriti in una mappa scratch per thread. All'uscita, il valore di ritorno viene abbinato ai dati di ingresso e inviato a un ring buffer. Lo spazio utente svuota il ring buffer tramite un fd asincrono e passa tutto attraverso la pipeline di filtro/decodifica.
kernel userspace
────── ─────────
raw_syscalls/sys_enter ──► MAPPA SYSCALL_ENTER (scratch per tid)
raw_syscalls/sys_exit ──► RING BUFFER EVENTI (4 MiB)
│
consumatore poll (tokio::spawn)
│
┌──────────┴──────────┐
RawOutput TuiApp
(una riga/syscall) (ratatui TUI)
I programmi eBPF sono scritti in Rust con aya, compilati in bytecode BPF al momento della compilazione e incorporati nel binario. Nessuna dipendenza runtime, nessun header del kernel.
git clone https://github.com/pandaadir05/snoop
cd snoop
# Nightly è necessario solo per il target BPF
rustup toolchain install nightly
rustup component add rust-src --toolchain nightly
# bpf-linker collega l'oggetto eBPF (nessun LLVM di sistema necessario)
cargo install bpf-linker --no-default-features
cargo build --release
sudo ./target/release/snoop -p $$
Lo script di build compila automaticamente i programmi eBPF. Nessun passaggio separato.
Durante lo sviluppo puoi anche usare xtask:
cargo xtask run -- -p $$
MIT o Apache-2.0, a tua scelta.
--pod <nome>--tls aggancia SSL_write/SSL_read tramite uprobe per mostrare il testo in chiaro--ltrace monitora malloc/free/calloc/reallocsnoop record salva su disco, snoop view riproduce offline (senza root)snoop diff before.snoop after.snoop mostra cosa è cambiato tra due esecuzioni--flamegraph out.svg| Tasto | Azione |
|---|
q | Esci |
Space | Pausa / riprendi |
/ | Ricerca incrementale |
f | Attiva/disattiva filtro filesystem |
n | Attiva/disattiva filtro rete |
c | Cancella lista eventi |
Enter | Mostra popup di dettaglio per l'evento selezionato |
↑ / k | Scorri su |
↓ / j | Scorri giù |
G / End | Vai all'evento più recente |
g / Home | Vai all'evento più vecchio |
| Layer | Crate |
|---|
| Programmi eBPF | aya-ebpf |
| Caricatore eBPF | aya |
| TUI | ratatui + crossterm |
| CLI | clap (derive) |
| Runtime asincrono | tokio |
| Flamegraph | inferno |