fako1024/slimcap

GitHub: fako1024/slimcap

一个纯 Go 的高性能网络数据包捕获库,通过零拷贝和 AF_PACKET ring buffer 在 Linux 上实现极低资源占用的流量抓包。

Stars: 14 | Forks: 1

# 一个高性能的网络数据包捕获库 [![Github Release](https://img.shields.io/github/release/fako1024/slimcap.svg)](https://github.com/fako1024/slimcap/releases) [![GoDoc](https://godoc.org/github.com/fako1024/slimcap?status.svg)](https://godoc.org/github.com/fako1024/slimcap/) [![Go Report Card](https://goreportcard.com/badge/github.com/fako1024/slimcap)](https://goreportcard.com/report/github.com/fako1024/slimcap) [![Build/Test Status](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/a2ebc4eac6131742.svg)](https://github.com/fako1024/slimcap/actions?query=workflow%3AGo) [![CodeQL](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/e05e8fafd8131743.svg)](https://github.com/fako1024/slimcap/actions/workflows/codeql.yml) 本包提供了一个简单而强大的接口,用于执行网络数据包捕获/嗅探。它专注于高性能/高流量吞吐量。 ## 功能特性 - 支持通过 AF_PACKET (Linux) 直接从网络 socket 或使用 ring buffer 进行原始负载/IP 层数据包捕获 - 极低的 CPU 使用率和内存(分配)占用,支持零拷贝操作 - 虚拟/模拟捕获源,包括从 PCAP 文件进行流量重放(甚至可以“链式”组合多个源) - 内置对数据包类型/方向检测的支持 - 使用原生 Go 编写(无 `CGO` 依赖) ## 安装说明 ``` go get -u github.com/fako1024/slimcap ``` ## 用法 #### **使用 `capture.Source` 接口的各种选项在网络接口上捕获少量数据包,使用固定的捕获长度(即 snaplen)为 64 字节:** ``` listener, err := afpacket.NewSource("enp1s0", afpacket.CaptureLength(link.CaptureLengthFixed(64)), ) if err != nil { // Error handling } // Capture a packet from the wire (allocate & copy) p, err := listener.NextPacket(nil) if err != nil { // Error handling } fmt.Printf("Received packet on enp1s0 (total len %d): %v (inbound: %v)\n", p.TotalLen(), p.Payload(), p.IsInbound()) // Capture a packet from the wire (copy to existing / reusable buffer packet) pBuf := listener.NewPacket() p, err := listener.NextPacket(pBuf) if err != nil { // Error handling } fmt.Printf("Received packet on enp1s0 (total len %d): %v (inbound: %v)\n", p.TotalLen(), p.Payload(), p.IsInbound()) // Capture a packet from the wire (function execution) if err := listener.NextPacketFn(func(payload []byte, totalLen uint32, pktType, ipLayerOffset byte) (err error) { fmt.Printf("Received packet on enp1s0 (total len %d): %v (inbound: %v)\n", totalLen, payload, pktType != capture.PacketOutgoing) return }); err != nil { // Error handling } // Close the listener / the capture if err := listener.Close(); err != nil { // Error handling } ``` #### **使用 `capture.SourceZeroCopy` 接口的各种选项在网络接口上执行零拷贝捕获少量数据包,使用最优捕获长度(即 snaplen)以确保可以访问 IPv4 和 IPv6 数据包的任何传输层,并设置自定义的 ring buffer 大小/块数量:** ``` listener, err := afring.NewSource("enp1s0", afring.CaptureLength(link.CaptureLengthMinimalIPv6Transport), afring.BufferSize((1<<20), 4), afring.Promiscuous(false), ) if err != nil { // Error handling } // Capture a raw packet (full payload) from the wire (zero-copy, no heap allocation) payload, pktType, totalLen, err := listener.NextPayloadZeroCopy() if err != nil { // Error handling } fmt.Printf("Received payload on enp1s0 (total len %d): %v (inbound: %v)\n", totalLen, payload, pktType != capture.PacketOutgoing) // Capture a packet (IP layer only) from the wire (zero-copy, no heap allocation) ipLayer, pktType, totalLen, err := listener.NextIPPacketZeroCopy() if err != nil { // Error handling } fmt.Printf("Received IP layer on enp1s0 (total len %d): %v (inbound: %v)\n", totalLen, ipLayer, pktType != capture.PacketOutgoing) // Close the listener / the capture if err := listener.Close(); err != nil { // Error handling } ``` 有关更多示例,请参考 [examples](./examples) 中的实现。一个使用 `slimcap` 并展示其所有功能(包括使用模拟源进行端到端测试)的生产级项目是 [goProbe](https://github.com/els0r/goProbe)。 ## 性能表现 以下基准测试(参见 [afring_mock_test.go](./capture/afpacket/afring/afring_mock_test.go))展示了单次数据包检索在 整体性能和内存分配占用方面的相对差异(在使用模拟捕获源的标准笔记本电脑上获得)。由于显而易见的原因,零拷贝模式表现最佳,因此应在高吞吐量场景中选用: ``` goarch: amd64 pkg: github.com/fako1024/slimcap/capture/afpacket/afring cpu: Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz BenchmarkCaptureMethods BenchmarkCaptureMethods/NextPacket 226401712 74.60 ns/op 64 B/op 1 allocs/op BenchmarkCaptureMethods/NextPacketInPlace 353661006 32.17 ns/op 0 B/op 0 allocs/op BenchmarkCaptureMethods/NextPayload 176332635 63.81 ns/op 48 B/op 1 allocs/op BenchmarkCaptureMethods/NextPayloadInPlace 516911223 21.65 ns/op 0 B/op 0 allocs/op BenchmarkCaptureMethods/NextPayloadZeroCopy 535092314 19.67 ns/op 0 B/op 0 allocs/op BenchmarkCaptureMethods/NextIPPacket 179753388 64.18 ns/op 48 B/op 1 allocs/op BenchmarkCaptureMethods/NextIPPacketInPlace 381187490 28.33 ns/op 0 B/op 0 allocs/op BenchmarkCaptureMethods/NextIPPacketZeroCopy 567278034 19.67 ns/op 0 B/op 0 allocs/op BenchmarkCaptureMethods/NextPacketFn 559334258 20.44 ns/op 0 B/op 0 allocs/op ``` ## 捕获原始数据包 默认情况下,`slimcap` 会根据链路类型自动定义 [BPF](https://docs.kernel.org/bpf/) 过滤器,将捕获的数据包限制为仅包含 IP 层的包。这样做是为了最大化性能并最小化 CPU/内存使用。如果需要捕获原始数据包(即捕获所有数据包而不管其负载内容),可以在创建新的捕获源时禁用自动 BPF 过滤器生成,例如: ``` listener, err := afring.NewSource(devName, afring.CaptureLength(filter.CaptureLengthFixed(64)), afring.BufferSize((1<<20), 4), afring.Promiscuous(false), afring.IgnoreVLANs(ignoreVLANs), afring.DisableAutoBPF(), // Disable automatic BPF filter generation ) ``` ## 捕获模拟 / 测试 为了在无需依赖_真实_网络接口捕获的情况下支持广泛的测试(直至端到端级别),普通的 AF_PACKET 和 ring buffer 捕获均提供了实现/封装其底层实际实现的模拟层源。因此,只需将任何对 `afpacket` 或 `afring` 源的调用替换为其对应的模拟版本即可,例如将: ``` listener, err := afring.NewSource("enp1s0", // Options ) ``` 更改为 ``` listener, err := afring.NewMockSource("enp1s0", // Options ) ``` 通过生成合成的数据包数据或从 PCAP 文件输入先前捕获的数据包,这些模拟源可以像实际的捕获源一样使用(例如用于测试目的)。关于如何使用模拟进行测试的一些好例子可以在 [afpacket_mock_test.go](./capture/afpacket/afpacket/afpacket_mock_test.go) 和 [afring_mock_test.go](./capture/afpacket/afring/afring_mock_test.go) 中找到。 由于模拟实现会产生较小但不可忽视的性能开销(即使在未使用时),`slimcap` 支持一个构建标签(build tag),允许完全禁用模拟(这反过来也会消除上述开销): ``` go build -tags slimcap_nomock ``` 建议在要求高性能的生产环境中使用此构建标签。 ## Bug 报告 & 功能请求 请使用 [issue tracker](https://github.com/fako1024/slimcap/issues) 提交 bug 和功能请求(或任何其他事项)。 ## 许可证 有关使用条件,请参见 [LICENSE](./LICENSE) 文件。
标签:AF_PACKET, EVTX分析, Golang, Libpcap替代, Linux网络, PCAP, Sniffer, 原生网络编程, 安全编程, 开发库, 抓包库, 日志审计, 流量回放, 目录遍历, 网络嗅探, 网络安全, 网络数据包捕获, 网络流量分析, 网络通信, 防御绕过, 隐私保护, 零拷贝, 高性能网络库