pandaadir05/snoop

GitHub: pandaadir05/snoop

一款基于 eBPF 的 Linux 系统调用追踪器,提供低开销实时 TUI、可视化过滤与 TLS 解密,替代传统 strace 提升观测效率。

Stars: 33 | Forks: 0

# snoop [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/4d46c5e017194510.svg)](https://github.com/pandaadir05/snoop/actions/workflows/ci.yml) [![License: MIT OR Apache-2.0](https://img.shields.io/badge/license-MIT%20OR%20Apache--2.0-blue.svg)](LICENSE) 一个基于 eBPF 的 Linux 系统调用追踪器。类似 strace,但提供实时 TUI、智能过滤器以及真正可读的参数解码。 ![snoop TUI demo](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/ec0472c33a194513.gif) ``` $ 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> ``` 或者不带 `--raw` 运行,以获得全屏 TUI: ``` 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? strace 使用 ptrace,会在每次系统调用时暂停进程。snoop 使用 eBPF tracepoints —— 进程保持全速运行,追踪在内核中完成。除了性能优势,snoop 还能将参数解码为可读内容、提供实时 TUI,并支持保存/回放/对比追踪。 ## 功能 - **TUI** — 实时滚动的系统调用流,包含顶部系统调用面板、搜索、类别过滤、暂停/恢复。当 stdout 不是终端时自动回退为 strace 风格的行输出。 - **输出格式** — `--raw`(strace 兼容)、`--json`(JSON Lines,供 jq 使用)、`--explain`(将系统调用归类为高层活动摘要) - **过滤** — `--files`、`--net`、`--slow 10`、`--syscall openat` - **参数解码** — 对 60 多种系统调用进行解码 — 路径、标志、套接字地址等,无需再查阅手册页 - **附加** — 可附加到运行中的进程(`-p PID`)或直接启动一个(`snoop `) - `--follow` — 同时追踪 fork 的子进程 - **容器** — `--docker ` 和 `--pod ` 可追踪容器内所有进程 - **TLS 捕获** — `--tls` 通过 uprobes 挂钩 `SSL_write`/`SSL_read` 显示明文 - **堆栈追踪** — `--ltrace` 跟踪 `malloc`/`free`/`calloc`/`realloc` - **记录与回放** — `snoop record` 保存到磁盘,`snoop view` 离线回放(无需 root) - **对比** — `snoop diff before.snoop after.snoop` 显示两次运行之间的差异 - **火焰图** — `--flamegraph out.svg` 无需内核模块,也无需 C 工具链。eBPF 程序使用纯 Rust(aya)编写,并内嵌在二进制文件中。 ## 系统要求 - Linux 5.8+(需要 BPF 环形缓冲区支持) - x86_64 或 aarch64 - 需 root 权限或 `CAP_BPF` + `CAP_PERFMON` ## 安装 ### 预编译二进制文件 ``` curl -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 ``` 对于 aarch64,请将 `x86_64` 替换为 `aarch64`。 ### 从源码编译 ``` cargo install --git https://github.com/pandaadir05/snoop snoop ``` 这会自动编译 eBPF 程序。不需要 C 工具链或内核头文件,只需要 Rust。 ## 使用方法 ``` # 跟踪命令 sudo snoop ls /etc sudo snoop -- nginx -g 'daemon off;' # 附加到正在运行的进程 sudo snoop -p $(pidof postgres) sudo snoop -p 1234 --follow # trace forked children too # 容器 sudo snoop --docker my-nginx sudo snoop --pod my-app-pod --namespace production # 过滤 sudo snoop -p 1234 --files # only file-system calls sudo snoop -p 1234 --net # only network calls sudo snoop -p 1234 --slow 5 # only calls slower than 5ms sudo snoop -p 1234 --syscall openat --syscall read ``` ### Explain 模式 `--explain` 会将原始系统调用聚合为高层摘要,而不是逐个显示: ``` sudo snoop -p 1234 --explain ``` ``` READ /etc/passwd ↓1.2 KB (2 calls, 0.80ms) NET 127.0.0.1:5432 ↑512 B ↓4.0 KB (18.20ms) EXEC /usr/bin/python3 ``` ### TLS 解密 挂钩 `SSL_write`/`SSL_read` 以捕获明文: ``` sudo snoop -p 1234 --tls ``` ### 堆栈追踪 ``` sudo snoop -p 1234 --ltrace ``` ### 记录与回放 记录追踪结果,之后可离线回放(无需 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")' ``` ### 对比两个追踪 适用于部署后定位回归问题: ``` sudo snoop record -p 1234 -o before.snoop # ... 部署更改 ... sudo snoop record -p 1234 -o after.snoop snoop diff before.snoop after.snoop ``` ``` SYSCALL COUNTS read 1200 → 1800 (+50.0%) ▲ openat 340 → 210 (-38.2%) ▼ DURATION REGRESSIONS (median) read 0.02ms → 0.08ms (+300%) ONLY IN after statx (4x) ``` ### JSON 输出 ``` sudo snoop -p 1234 --json | jq 'select(.name == "connect")' ``` ### 导出火焰图 ``` sudo snoop -p 1234 --flamegraph syscalls.svg ``` ## 标志 ``` -p, --pid Attach to a running process --follow Trace forked children (requires --pid) --docker Trace all processes in a Docker container --pod Trace all processes in a Kubernetes pod -n, --namespace Kubernetes namespace (default: default) --raw One-line strace-compatible output --json JSON Lines — one object per syscall --explain Semantic activity summaries --files File-system syscalls only --net Network syscalls only --slow Only calls slower than threshold --syscall Only this syscall (repeatable) --no-decode Raw hex arguments, no decoding --tls Capture TLS plaintext via SSL_write/SSL_read uprobes --ltrace Trace malloc/free/calloc/realloc --flamegraph Write flamegraph SVG on exit --ebpf-obj Override embedded eBPF object [$SNOOP_EBPF_OBJ] ``` ## TUI 按键绑定 | 按键 | 操作 | | --- | --- | | `q` | 退出 | | `Space` | 暂停 / 恢复 | | `/` | 增量搜索 | | `f` | 切换文件系统过滤 | | `n` | 切换网络过滤 | | `c` | 清除事件列表 | | `Enter` | 显示选中事件的详情弹窗 | | `↑` / `k` | 向上滚动 | | `↓` / `j` | 向下滚动 | | `G` / `End` | 跳至最新事件 | | `g` / `Home` | 跳至最早事件 | ## 工作原理 两个 eBPF 程序分别挂载到 `raw_syscalls/sys_enter` 和 `sys_exit`。在进入时,系统调用号和参数写入每个线程的暂存 Map;在退出时,返回值与入口数据配对并推送到环形缓冲区。 用户空间通过异步 fd 读取环形缓冲区,并经过过滤/解码管道处理。 ``` kernel userspace ────── ───────── raw_syscalls/sys_enter ──► SYSCALL_ENTER map (per-tid scratch) raw_syscalls/sys_exit ──► EVENTS ring buffer (4 MiB) │ poll consumer (tokio::spawn) │ ┌──────────┴──────────┐ RawOutput TuiApp (one line/syscall) (ratatui TUI) ``` eBPF 程序使用 Rust 与 [aya](https://github.com/aya-rs/aya) 编写,在构建时编译为 BPF 字节码并内嵌到二进制文件中。无运行时依赖,也无需内核头文件。 ## 从源码构建 ``` git clone https://github.com/pandaadir05/snoop cd snoop # Nightly 仅适用于 BPF 目标 rustup toolchain install nightly rustup component add rust-src --toolchain nightly # bpf-linker 链接 eBPF 对象(无需系统 LLVM) cargo install bpf-linker --no-default-features cargo build --release sudo ./target/release/snoop -p $$ ``` 构建脚本会自动编译 eBPF 程序,无需额外步骤。 开发过程中也可使用 xtask: ``` cargo xtask run -- -p $$ ``` ## 技术栈 | 层级 | Crate | | --- | --- | | eBPF 程序 | `aya-ebpf` | | eBPF 加载器 | `aya` | | TUI | `ratatui` + `crossterm` | | CLI | `clap`(derive) | | 异步运行时 | `tokio` | | 火焰图 | `inferno` | ## 许可证 MIT 或 Apache-2.0,任选其一。
标签:Go, Linux 调试, Ruby工具, Rust, strace 替代, syscall tracer, TLS 解密, TUI 界面, 二进制发布, 可视化界面, 可读输出, 子域名生成, 开源工具, 性能分析, 智能过滤, 系统追踪, 网络流量审计, 网络调试, 自动化, 通知系统