mar0ls/tcpdump_go
GitHub: mar0ls/tcpdump_go
基于 Go 语言和 gopacket 构建的网络数据包捕获与分析 CLI 工具,兼容 tcpdump 标志集并在 Hex 输出性能上大幅领先,同时新增文件轮转、CSV 流导出和统计摘要等功能。
Stars: 0 | Forks: 0
# 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文件处理, 二进制发布, 嗅探器, 开源工具, 抓包工具, 日志审计, 服务管理, 流量导出, 程序破解, 网络协议分析, 网络安全, 网络数据包捕获, 网络流量分析, 运维工具, 防御绕过, 隐私保护