mar0ls/tcpdump_go

GitHub: mar0ls/tcpdump_go

基于 Go 语言和 gopacket 构建的网络数据包捕获与分析 CLI 工具,兼容 tcpdump 标志集并在 Hex 输出性能上大幅领先,同时新增文件轮转、CSV 流导出和统计摘要等功能。

Stars: 0 | Forks: 0

# tcpdump_go ![Go](https://img.shields.io/badge/Go-1.25+-00ADD8?logo=go&logoColor=white) ![Platform](https://img.shields.io/badge/platform-linux%20%7C%20macOS%20%7C%20windows-lightgrey) ![License](https://img.shields.io/badge/license-MIT-green) ![docs](https://img.shields.io/badge/docs-generated-blue) [![Release](https://img.shields.io/github/v/release/mar0ls/tcpdump_go)](https://github.com/mar0ls/tcpdump_go/releases/latest) 使用 Go 编写的网络数据包分析器,基于 [gopacket](https://github.com/gopacket/gopacket) 和 libpcap 构建。 兼容 tcpdump 的标志集,并增加了额外功能:pcap 文件轮转、流 CSV 导出、彩色输出以及详细统计。 ## 要求 - Go 1.25+ - libpcap (`sudo apt install libpcap-dev` / `brew install libpcap`) - 实时捕获需要 root 权限或 `CAP_NET_RAW` 能力 - **Windows:** 使用 [Npcap](https://npcap.com/) 替代 libpcap ## 安装 ``` git clone https://github.com/mar0ls/tcpdump_go.git cd tcpdump_go go build -o tcpdump_go . ``` ## 使用方法 ``` sudo ./tcpdump_go [options] [BPF expression] ``` 不带 `-i` 运行会列出所有可用接口。 ## 标志 单字母标志可以按 POSIX 风格组合使用:`-nXX`、`-nvXX`、`-ntttt` 等。 ``` Source: -i Network interface (no -i: list available) -r Read from .pcap or .pcapng file -f BPF filter, e.g. 'tcp port 443' -c Capture/process only N packets Output: -w Write packets to .pcap file -rotate-size N Rotate -w file after N bytes -rotate-time N Rotate -w file every N seconds -csv Write flows to CSV (only with -r) Capture: -s Max bytes per packet (default: 65535) -B Kernel pcap buffer in KB (default: 2048 KB) -promisc Promiscuous mode — enabled by default -disable-offload Disable NIC offloading via ethtool (Linux, root) View: -v Verbose: tos/ttl/id/offset/flags/proto + seq/ack/win for TCP -x Hex without Ethernet header -X Hex + ASCII without Ethernet header -xx Hex with Ethernet header -XX Hex + ASCII with Ethernet header Timestamp (compatible with tcpdump): -t No timestamp -tt Unix timestamp (seconds.microseconds) -ttt Delta from previous packet -tttt Date + time (2006-01-02 15:04:05.000000) Misc: -n Disable reverse DNS -q Quiet mode — no packet output (use with -stats) -stats Print statistics summary on exit ``` ## 示例 ``` # 列出可用接口 sudo ./tcpdump_go # 在 eth0 上捕获 HTTP 流量 sudo ./tcpdump_go -i eth0 -f "tcp port 80" # 前 100 个数据包,无 DNS,详细输出 — POSIX 风格标志 sudo ./tcpdump_go -i eth0 -c 100 -nv # 十六进制+ASCII 带以太网报头,无 DNS sudo ./tcpdump_go -i eth0 -nXX # 日期 + 时间(类似 tcpdump -tttt) sudo ./tcpdump_go -i eth0 -ntttt # 数据包间时间差 sudo ./tcpdump_go -i eth0 -nttt # 使用 BPF filter 写入 pcap sudo ./tcpdump_go -i eth0 -f "not port 22" -w capture.pcap # 每 100 MB 轮转一次 sudo ./tcpdump_go -i eth0 -w capture.pcap -rotate-size 104857600 # 每 60 秒轮转一次 sudo ./tcpdump_go -i eth0 -w capture.pcap -rotate-time 60 # 用于突发流量的大容量 kernel buffer(64 MB) sudo ./tcpdump_go -i eth0 -B 65536 # 仅统计,无数据包输出 sudo ./tcpdump_go -i eth0 -q -stats # 使用十六进制+ASCII 视图读取 pcap 文件 ./tcpdump_go -r capture.pcap -nX # 将流导出至 CSV ./tcpdump_go -r capture.pcap -csv flows.csv # 捕获前禁用 NIC offloading(Linux,root) sudo ./tcpdump_go -i eth0 -disable-offload ``` ## 性能与 tcpdump 对比 测试文件:**15 MB pcap,17 361 个数据包**。平台:macOS arm64 (Apple Silicon M 系列)。 测量方式:`time ./binary -r file > /dev/null`。 | 模式 | tcpdump | tcpdump_go | 差异 | | ---- | ------- | ---------- | ---------- | | Normal (`-n`) | 0.040s | **0.038s** | 相当 | | Verbose (`-nv`) | 0.035s | **0.032s** | 相当 | | Hex (`-nx`) | 0.497s | **0.042s** | **快 11.8×** | | Hex+ASCII (`-nX`) | 0.462s | **0.104s** | **快 4.4×** | | Hex+ASCII with L2 (`-nXX`) | 0.467s | **0.105s** | **快 4.4×** | ### 为什么 Hex 模式更快 tcpdump 使用 `fprintf("%02x", byte)` —— 每个字节一次系统调用。tcpdump_go 使用: - **查找表** `hexTable` —— 半字节转十六进制,无需格式化调用 - **`sync.Pool`** 预分配缓冲区 —— 每行零内存分配 - **`bufio.Writer` 256 KB** —— 每约 200 行进行一次 stdout 系统调用 - **worker goroutine** —— 写入和打印与捕获并行执行 ### GOGC=off 用于文件处理 对于产生大量分配的模式(gopacket 会为每个数据包对象进行分配),可以禁用 GC: ``` GOGC=off ./tcpdump_go -r capture.pcap -n ``` `GOGC=off` 是一个**运行时环境变量**,而不是编译器标志。它对二进制文件本身没有影响。 在 15 MB pcap 上的效果:正常 0.038s → **0.027s**(约快 30%)。 注意:在实时捕获时,它会导致无限增长的内存消耗 —— 仅在使用 `-r` 时使用。 ## 操作系统内核如何处理数据包 ### Linux ``` NIC → DMA ring buffer (kernel) → BPF filter (kernel) → libpcap ring (mmap) → userspace ``` 1. **NIC DMA 环形缓冲区** —— NIC 通过 DMA 将数据包直接写入内核内存,无需 CPU 参与。 2. **内核中的 BPF 过滤器** —— 过滤器(`-f "tcp port 443"`)被 JIT 编译,并在数据包离开内核*之前*进行评估。不匹配的数据包永远不会被复制到用户空间。 3. **TPACKET_V3 环形缓冲区** —— libpcap 自动与内核协商共享内存映射(`mmap`)。数据包直接进入共享缓冲区 —— 从内核到用户空间的**零拷贝**。gopacket 中的 `NoCopy=true` 避免了进一步的拷贝。 4. **调优**: - `sysctl -w net.core.rmem_max=536870912` —— 最大缓冲区 512 MB - `-B 65536` (64 MB) —— libpcap 缓冲区大小 - `-disable-offload` —— 禁用在 BPF 之前合并/拆分数据包的 TSO/GRO ### macOS ``` NIC → IOKit driver → BPF device (/dev/bpf0) → userspace read() ``` 1. **BPF 设备** —— 伯克利数据包过滤器,最初的 BSD 实现。通过 `/dev/bpfN` 访问。 2. **BPF 批处理** —— 默认情况下,`read()` 会一次返回*多个*数据包(当缓冲区满或超时时)。`ImmediateMode=true` 禁用超时并立即交付数据包 —— 延迟更低,但牺牲了批处理能力。 3. **`BIOCSBLEN`** (SetBufferSize) —— 设置 BPF 缓冲区大小。默认约 32 KB;我们默认设置为 **2 MB**。 4. **在卸载之前** —— macOS 的 BPF 在硬件卸载*之前*捕获数据包,因此不需要 `-disable-offload`。 5. **调优**:通过 `/etc/sysctl.conf` 设置 `kern.ipc.maxsockbuf` ### Windows (Npcap) ``` NIC → NDIS miniport driver → Npcap kernel driver → WinPcap API → userspace ``` 1. **NDIS 过滤驱动** —— Npcap 作为 NDIS 轻量级过滤器 (LWF) 驱动程序安装,在网络驱动级别拦截数据包。 2. **内核模式缓冲区** —— Npcap 在内核内存中缓冲数据包,并通过 DeviceIoControl/ReadFile 将其传送到用户空间。 3. **无 TPACKET_V3** —— Windows 没有等效的 mmap 环形缓冲区;每次 `ReadFile` 都会进行从内核到用户空间的数据拷贝。 4. **调优**:通过 Npcap 安装程序或 `SetBufferSize`(通过 libpcap API)设置缓冲区大小。 ## 与 tcpdump 的功能比较 | 功能 | tcpdump | tcpdump_go | | ------- | ------- | ---------- | | 实时捕获 | ✓ | ✓ | | BPF 过滤器 | ✓ | ✓ | | 读取 pcap/pcapng (`-r`) | ✓ | ✓ | | 写入 pcap (`-w`) | ✓ | ✓ | | 混杂模式 | ✓ | ✓ | | 内核缓冲区 (`-B`) | ✓ | ✓ | | 立即模式 | ✓ | ✓ | | 数据包限制 (`-c`) | ✓ | ✓ | | Hex 转储 (`-x/-X/-xx/-XX`) | ✓ | ✓ | | 详细 IP/TCP/UDP (`-v`) | ✓ | ✓ | | 时间戳标志 (`-t/-tt/-ttt/-tttt`) | ✓ | ✓ | | POSIX 风格组合标志 (`-nXX`) | ✓ | ✓ | | ARP 解码 | ✓ | ✓ | | 输出中的数据包编号 | ✗ | ✓ | | pcap 文件轮转 (`-rotate-size/time`) | ✗ | ✓ | | tshark 风格的统计信息 (`-stats`) | ✗ | ✓ | | 流 CSV 导出 (`-csv`) | ✗ | ✓ | | 彩色输出 | ✗ | ✓ | | 带缓存的反向 DNS | ✗ | ✓ (无重复查找) | | 禁用 NIC 卸载 | ✗ | ✓ (Linux, `-disable-offload`) | | Hex 转储快 4–12× | ✗ | ✓ (查找表 + sync.Pool) | | 1 MB pcap 写入缓冲区 | ✗ | ✓ (约 30 次系统调用/秒,而不是 16 000 次) | ## 统计信息 (`-stats`) ``` ── Session summary ────────────────────────── Duration : 2m15.3s Packets total : 129030 (954 pkt/s) Bytes total : 66637452 (3940.8 kbps) Packet size : min=42 avg=516 max=1514 B ── Protocol hierarchy ──────────────────────── Protocol Packets Share TCP 84201 65.3% UDP 44411 34.4% ICMP 418 0.3% ── TCP flags ──────────────────────────────── SYN: 1203 FIN: 987 RST: 42 ── Top 5 senders ──────────────────────────── 192.168.1.100 45231 ... ``` ## CSV 导出 (`-csv`) 仅在使用 `-r` 时可用。以类似 NetFlow 的格式生成聚合流: ``` src_ip,dst_ip,src_port,dst_port,proto,count 192.168.1.5,8.8.8.8,54321,53,UDP,42 192.168.1.5,93.184.216.34,54400,443,TCP,158 ``` 适用于在 Python、Excel 或 SIEM 工具中进行分析。 ## 丢弃的数据包 在缓冲区配置正确的情况下,内核丢弃数为零。 在统计信息 (`-stats`) 中显示为 `Dropped (pcap)`。 ### 捕获架构(2 个 goroutine) ``` libpcap → [capture goroutine] → captureCh (buffered) → [worker goroutine] → print/pcap/stats ``` 捕获 goroutine **只做一件事**:将数据包排入 channel。不进行 I/O 操作。 worker 按照自己的节奏进行处理。在按下 Ctrl+C/SIGTERM 时:优雅排空 —— channel 中的任何数据包都不会丢失。 ### 减少丢包 ``` # 大容量 kernel buffer(64 MB) sudo ./tcpdump_go -i eth0 -B 65536 # 提高系统限制(Linux) sudo sysctl -w net.core.rmem_max=536870912 # 更小的 snaplen = 每个数据包更少的数据 sudo ./tcpdump_go -i eth0 -s 96 # BPF filter — kernel 在拷贝前丢弃不需要的数据包 sudo ./tcpdump_go -i eth0 -f "tcp port 443" # 禁用反向 DNS sudo ./tcpdump_go -i eth0 -n ``` ### 内核限制 | 操作系统 | 默认 pcap 缓冲区 | tcpdump_go 默认值 | 如何增加 | | -- | ------------------- | ------------------ | --------------- | | Linux | ~208 KB | 2 MB | `sysctl -w net.core.rmem_max=536870912` | | macOS | ~32 KB (BPF) | 2 MB | 在 `/etc/sysctl.conf` 中设置 `kern.ipc.maxsockbuf=268435456` | | Windows | ~1 MB (Npcap) | 2 MB | Npcap 安装程序 → 缓冲区大小 | ## NIC 卸载(`-disable-offload`,仅限 Linux) 现代 NIC 会将一些 CPU 工作卸载到硬件上。在捕获期间,这可能会产生“被修改”的数据包。 | ethtool 选项 | 未禁用时的效果 | | -------------- | ------------------------ | | `tso` (TX Segmentation Offload) | TCP 分段高达 64 KB,而不是约 1500 B | | `gro` (Generic Receive Offload) | 多个小数据包合并为一个 | | `rxvlan` | VLAN 标签在 pcap 中不可见 | | `rx/tx` 校验和卸载 | pcap 中的校验和不正确 | ``` sudo ./tcpdump_go -i eth0 -disable-offload # disable + start capture ``` 效果是暂时的 —— 重启后重置。macOS 在卸载之前进行捕获 —— 不需要此标志。 ## 输出 | 流 | 内容 | 缓冲 | | ------ | ------------------- | ---------------------- | | stdout | 数据包,统计信息 | 256 KB `bufio.Writer` | | stderr | 警告,错误 | 无缓冲 | ``` sudo ./tcpdump_go -i eth0 2>/dev/null # packets only sudo ./tcpdump_go -i eth0 > packets.log # packets to file sudo ./tcpdump_go -i eth0 > packets.log 2> errors.log ```
标签:BPF过滤, EVTX分析, gopacket, Go语言, pcap文件处理, 二进制发布, 嗅探器, 开源工具, 抓包工具, 日志审计, 服务管理, 流量导出, 程序破解, 网络协议分析, 网络安全, 网络数据包捕获, 网络流量分析, 运维工具, 防御绕过, 隐私保护