有些项目启动前会列好路线图。skbx 的起点则是我一头扎进 Linux 网络的兔子洞,结果发现比预期有意思太多。
最开始的问题很简单:这个包到底去了哪里?一个数据包能穿过网络命名空间、路由决策、Netfilter、流控、XDP 程序、隧道、克隆、拷贝,还会在各种丢弃路径上消失。你在某个接口抓包,抓到的内容可能完全正确,但那只是完整旅程中的一个片段。
我想看到更多旅程。而且不光要看,我还想保存下来,之后不用 root 权限就能重放,同时让自己知道抓包过程本身有没有丢失观测。
skbx 就是一个用 Rust 和 CO-RE eBPF 实现的 Linux 包路径飞行记录器。在实时抓包阶段,它会观察内核网络函数,并把观测结果写入一个只追加的 JSONL 证据流。抓包结束后,那条证据流可以重放、查探,完全不必再加载 eBPF 程序。
它的工作流大致是这样的:实时流量进入,CO-RE eBPF 产生观测,这些观测写进有界的 traceq JSONL 流,随后可以重放、生成路由模式、解释某个事件。
skbx 能观察的范围覆盖内核多个网络路径上的关键函数。但它不是 tcpdump 或者 Wireshark 的替代品。那些工具在回答“抓包点的包字节与协议解析”这种问题时非常出色。而 skbx 是为“数据包在本地 Linux 内核里的路径”这类问题设计的。
它也不是第一个沿着内核路径追踪数据包的工具。这个项目明确受到了 pwru 的启发——pwru 已经展示了基于 eBPF 的广泛包追踪能有多实用。
我自己特别想深入探索的,是实时终端停止滚动之后的证据部分。实时追踪当然有用,但事件处置往往会在特权会话结束后继续进行。可能会有其他人需要查看这次抓包内容,我们也可能想把它和一次成功请求做比较,或者在 Bug 报告中精确引用某一次具体事件。自动化系统或者 AI 系统可能需要结构化的输入,但它们绝不应该被允许“发明”那些从未抓到的观测。
所以 skbx 原生的 stream 格式,也就是 traceq,带有一个信封结构:capture_start、若干 event、最后是 capture_end。每一个事件都会获得一个稳定的句柄,形如 event:111111111111111111111111。重放时,有序的事件会被归组为有界的路由模式,路由模式也会拿到各自的句柄,比如 route:1c0201e74424e253f8363577。
尾部信息和事件本身同样重要。它记录了停止原因以及一系列可靠性计数器:内核预留失败次数、追踪器递归遗漏次数、读取失败次数、用户态解码和富化失败次数、输出失败次数。如果尾部缺失,那么这个产物就是不完整的。如果追踪器丢掉了观测,这种不确定性会一直挂在结果上。
我挺喜欢这个特性的,因为追踪软件本身也是软件,它不应该悄无声息地假装全知全能。目前实时追踪器的部分还在演进中,但它已经能提供一条有迹可循、可事后审计的包路径证据链。
热门跟贴