基于 libpcap 的轻量级网络包嗅探与协议分析工具。从链路层到应用层逐层解析,支持实时抓包、BPF 过滤、PCAP 文件读写、DNS/HTTP 解析和实时流量统计。
项目信息: 题目 #07 | 双人协作 | 周期 2 周(10 个工作日)
当前阶段: 全部功能已完成 — 抓包/过滤/解析/统计/文件读写/TCP重组/TLS SNI/ncurses UI
开发文档: 项目开发计划书.md
main.c — 入口,CLI 参数解析,双线程调度
├── capture.c/h — libpcap 抓包引擎(混杂模式,256MB 内核缓冲)
├── filter.c/h — BPF 过滤器编译与应用
├── pcap_io.c/h — PCAP 文件读写(-w 实时保存,-r 离线回放)
├── ring_buffer.c/h — 线程安全环形缓冲区(pthread 互斥锁 + 条件变量)
├── protocol.c/h — 协议解析:ETH → IPv4/IPv6 → TCP/UDP/ICMP → DNS/HTTP
├── tcp_reasm.c/h — TCP 流重组(五元组哈希表 + SEQ 排序 + 状态机)
├── ip_reasm.c/h — IP 分片重组(IPv4/IPv6,超时回收)
├── http_extract.c/h— HTTP 完整报文提取(请求/响应行 + Header 解析)
├── tls_parser.c/h — TLS 握手识别与 SNI 域名提取
├── stats.c/h — 实时流量统计(7 类协议,每秒刷新,含速率)
└── ui.c/h — ncurses 终端界面(包列表/协议树/Hex/过滤/搜索/保存)
多线程 + UI 架构:
capture 线程 主线程 (ncurses UI)
│ │
pcap_loop() │
│ │
pcap_callback() │
├─ pcap_dump (if -w) │
└─ rb_push() ──→ [ring_buffer] ──→ rb_pop_timeout()
│
quick_parse() → 显示
stats_update()
│
┌─────────────────────┐
│ Packet List │
│ Protocol Tree/Hex │
│ Traffic Stats │
│ f:filter w:save │
└─────────────────────┘
dispatch_packet() └─ parse_eth() —— 以太网帧(L2) ├─ parse_ipv4() —— IPv4(L3) │ ├─ parse_tcp() —— TCP(L4)→ parse_http() │ ├─ parse_udp() —— UDP(L4)→ parse_dns() │ └─ parse_icmp() —— ICMP(L4) └─ parse_ipv6() —— IPv6(L3,支持扩展头遍历) ├─ parse_tcp() ├─ parse_udp() └─ parse_icmp()
---
## 环境要求
| 依赖 | 说明 |
|------|------|
| **libpcap**(必需) | 底层抓包引擎,Windows 下为 [Npcap](https://npcap.com/) |
| **GCC / MinGW**(必需) | 编译工具链 |
| **make**(可选) | 使用 Makefile 构建 |
### Windows 环境搭建
1. 安装 [Npcap](https://npcap.com/)(勾选 "Install in WinPcap API-compatible Mode")
2. 安装 [MSYS2](https://www.msys2.org/) → `pacman -S mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-pkg-config make`
3. 安装 libpcap for MinGW:
```bash
pacman -S mingw-w64-ucrt-x86_64-libpcap
- 将
ucrt64/bin加入系统 PATH - 在 MSYS2 或 Git Bash 下执行构建
sudo apt install build-essential libpcap-dev # Debian/Ubuntu
sudo dnf install gcc make libpcap-devel # Fedora# 编译主程序
make
# 编译并运行(需 root / 管理员权限)
make run
# 编译并运行协议解析单元测试(无需 root)
make test
# 详细模式运行测试(输出每个用例的解析日志)
make test-verbose
# 清理构建产物
make clean输出目标文件为 my_sniffer(Linux)或 my_sniffer.exe(Windows)。
gcc -Wall -Wextra -O2 -g -Iinclude \
src/main.c src/capture.c src/filter.c src/protocol.c \
src/stats.c src/pcap_io.c src/ring_buffer.c \
src/tcp_reasm.c src/ip_reasm.c src/http_extract.c \
-lpcap -lpthread -o my_sniffer# 1. 查看帮助
./my_sniffer -h
# 2. 自动选择网卡捕获所有流量(Ctrl+C 停止)
sudo ./my_sniffer
# 3. 仅捕获 HTTP 流量
sudo ./my_sniffer -f "tcp port 80"
# 4. 捕获并保存到文件
sudo ./my_sniffer -f "udp port 53" -w dns_only.pcap
# 5. 离线回放之前保存的文件
./my_sniffer -r dns_only.pcapUsage: my_sniffer [options]
Options:
-i <iface> 网络接口名称(默认:自动选择第一个可用接口)
-f <filter> BPF 过滤表达式(如 "tcp port 80",默认:无过滤)
-r <file> 从 PCAP 文件读取并回放数据包
-w <file> 将实时捕获的数据包写入 PCAP 文件
-h 显示帮助信息
# Linux
ip link show
tcpdump --list-interfaces
# Windows(Npcap)
.\my_sniffer.exe -i help
# 或从设备管理器 / Npcap 控制台获取 \Device\NPF_{...}不指定 -i 时自动选择第一个可用接口:
# 全量捕获(所有流量)
sudo ./my_sniffer
# 指定接口捕获
sudo ./my_sniffer -i eth0
sudo ./my_sniffer -i "Wi-Fi" # Windows
sudo ./my_sniffer -i enp0s3 # Linux使用 Berkeley Packet Filter 语法过滤流量:
# 按协议
sudo ./my_sniffer -f "tcp"
sudo ./my_sniffer -f "udp"
sudo ./my_sniffer -f "icmp"
# 按端口
sudo ./my_sniffer -f "tcp port 80" # HTTP
sudo ./my_sniffer -f "tcp port 443" # HTTPS
sudo ./my_sniffer -f "udp port 53" # DNS
sudo ./my_sniffer -f "tcp port 22" # SSH
# 按主机
sudo ./my_sniffer -f "host 192.168.1.1"
sudo ./my_sniffer -f "src host 10.0.0.1"
sudo ./my_sniffer -f "dst host 8.8.8.8"
# 复合条件
sudo ./my_sniffer -f "tcp port 80 and host 192.168.1.100"
sudo ./my_sniffer -f "tcp port 80 or udp port 53"
sudo ./my_sniffer -f "not arp and not icmp"测试过滤功能:
# 终端 1:启动嗅探器过滤 HTTP
sudo ./my_sniffer -f "tcp port 80"
# 终端 2:发 HTTP 请求验证
curl http://example.com将实时捕获的数据包保存为 PCAP 文件,可用 Wireshark 或 -r 回放:
# 捕获 HTTP 流量并保存
sudo ./my_sniffer -f "tcp port 80" -w http_capture.pcap
# 捕获全量流量保存
sudo ./my_sniffer -w full_capture.pcap验证保存的文件:
# 方法 1:用本工具回放
./my_sniffer -r http_capture.pcap
# 方法 2:用 Wireshark / tcpdump 打开
tcpdump -r http_capture.pcap
wireshark http_capture.pcap从之前保存的 PCAP 文件读取数据包,解析输出到终端。无需 root 权限:
# 基本回放
./my_sniffer -r http_capture.pcap
# 回放 + 过滤(只分析回放文件中符合条件的包)
./my_sniffer -r full_capture.pcap -f "udp port 53"
# 使用测试用 PCAP 文件
wget https://wiki.wireshark.org/SampleCaptures/http.cap
./my_sniffer -r http.cap# 实时抓 UDP 53 端口的 DNS 流量 + 保存到文件
sudo ./my_sniffer -f "udp port 53" -w dns.pcap
# 离线回放 DNS 文件 + 再过滤到特定主机
./my_sniffer -r dns.pcap -f "host 8.8.8.8"启动后进入全屏 TUI:
sudo ./my_sniffer # 实时抓包 + UI
sudo ./my_sniffer -f "tcp port 80" # BPF 过滤 + UI
./my_sniffer -r capture.pcap # 离线回放 + UI| 按键 | 功能 |
|---|---|
↑ ↓ PgUp PgDn Home End |
导航包列表 |
Enter |
展开/折叠协议树 |
h |
切换 Hex dump 视图(原始字节) |
s |
切换统计面板 ON/OFF |
f |
显示过滤:输入关键字(proto/port/IP),ESC 清除 |
n |
跳到下一个匹配的包 |
w |
交互式保存 pcap:输入文件名,自动追加 .pcap,再次按 w 停止 |
q |
退出 |
状态栏显示:包总数、BPF 过滤条件、保存状态、[EOF] 离线回放结束标记。
每个数据包从链路层到应用层逐层打印一行摘要。
ETH : aa:bb:cc:dd:ee:ff -> 11:22:33:44:55:66 | type=0x0800(IPv4)
aa:bb:cc:dd:ee:ff= 源 MAC,11:22:33:44:55:66= 目的 MACtype=0x0800(IPv4)/0x86DD(IPv6)/0x0806(ARP)- 如为 VLAN 标签帧(type=0x8100),自动解析并打印内层 EtherType:
ETH : ... | type=0x8100(VLAN) [VLAN: PCP=0 DEI=0 VID=100] ETH : inner type=0x0800(IPv4)
IPv4: 192.168.1.100 -> 93.184.216.34 | proto=6(TCP) ttl=64 ihl=20 total_len=1500 id=0x3a2b frag=@0 cksum=0xabcd
proto=6(TCP)/17(UDP)/1(ICMP)frag=DF@0= DF 标志 + 片偏移,非首分片自动跳过
IPv6: 2001:db8::1 -> 2606:2800:220::1 | next=6(TCP) hlim=64 plen=1440 tc=0x00 fl=0x00000
- 自动遍历 IPv6 扩展头(Hop-by-Hop、Routing、Fragment、Dest Opt、AH)
- 遇 Fragment Header 且非首分片时自动跳过
- 扩展头信息实时打印:
[IPv6 Fragment: next=6 offset=0 mf=0 id=0xabcdef01]
TCP : 49234 -> 80 | seq=0x12345678 ack=0x87654321 flags=SYN win=65535 cksum=0xabcd urg=0 hdr=20
TCP : 49234 -> 80 | seq=0x12345679 ack=0x87654322 flags=PSH+ACK win=65535 cksum=0xabcd urg=0 hdr=20
- 标志位字符串:
SYN/SYN+ACK/PSH+ACK/FIN+ACK/RST/None - 常见应用层自动附加解析:端口 80/8080 → HTTP
UDP : 5353 -> 53 | len=48 cksum=0xabcd
- 端口 53 自动附加 DNS 解析
ICMP: type=8(Echo Request) code=0 cksum=0xabcd id=1 seq=1
ICMPv6: type=128(Echo Request) code=0 cksum=0xabcd id=1 seq=1
- 支持 15 种 ICMPv4 类型、13 种 ICMPv6 类型(含 NDP、MLD)
DNS : id=0x1234 Query op=QUERY qd=1 an=0 ns=0 ar=1
DNS : query[0]: www.example.com (A, class=1)
响应包增加回答区解析:
DNS : id=0x1234 Response op=QUERY qd=1 an=2 ns=0 ar=0 rcode=0(OK)
DNS : query[0]: www.example.com (A, class=1)
DNS : answer[0]: www.example.com -> A 93.184.216.34
DNS : answer[1]: www.example.com -> AAAA 2606:2800:220:1:248:1893:25c8:1946
- 支持 A、AAAA、CNAME、NS、MX、TXT、PTR、SOA、SRV 记录类型
- DNS 域名解压支持压缩指针(RFC 1035),含循环指针防护
请求行:
TCP : 49234 -> 80 | seq=0x... ack=0x... flags=PSH+ACK win=... cksum=0x... urg=0 hdr=20
HTTP: GET /index.html HTTP/1.1
HTTP: POST /api/login HTTP/1.1
响应行:
HTTP: Response HTTP/1.1 200 OK
HTTP: Response HTTP/1.1 404 Not Found
HTTP: Response HTTP/1.1 500 Internal Server Error
- 支持 9 种 HTTP 方法:GET、POST、HEAD、PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH
- 支持 28 种 HTTP 状态码(100~504)
- 仅解析单 TCP 段内的首行,分片 HTTP 需等 TCP 重组阶段
抓包过程中每秒自动刷新当前协议分布统计:
--------------------------------------------------
Proto Packets Bytes
--------------------------------------------------
TCP 42 32000
UDP 15 2400
ICMP 2 196
HTTP 18 21400
HTTPS 24 38500
DNS 12 1200
--------------------------------------------------
Total 113 95696
--------------------------------------------------
统计覆盖 7 个分类:TCP、UDP、ICMP、HTTP、HTTPS、DNS、OTHER。
make test运行 53 个测试用例,覆盖:
- ✅ 各层正常协议路径(ETH→IPv4→TCP→HTTP、ETH→IPv4→UDP→DNS)
- ✅ 截断包检测
- ✅ 畸形字段检测(版本错误、IHL 越界、非法偏移)
- ✅ 异常包防御(DNS 大计数、自引用循环指针)
- ✅ VLAN 标签、IPv6 扩展头
- ✅ 空指针 / 零长度
# 1. 实时抓包+BPF过滤
sudo ./my_sniffer -f "tcp port 80"
# 2. 抓包+实时保存
sudo ./my_sniffer -f "udp port 53" -w dns.pcap
# 3. 离线回放
./my_sniffer -r dns.pcap
# 4. 回放+二次过滤
./my_sniffer -r dns.pcap -f "host 8.8.8.8"
# 5. 统计观察
sudo ./my_sniffer
# 同时执行 curl / nslookup / ping 查看统计变化- 基于 libpcap 的
pcap_loop()事件驱动抓包 - 自动选择网卡或用户通过
-i指定 - 32MB 内核缓冲区,高流量下降低丢包
- 数据结构链路层校验(仅支持 DLT_EN10MB)
SIGINT/SIGTERM安全终止
- 封装
pcap_compile()+pcap_setfilter() - 支持完整 BPF 表达式语法(同 tcpdump)
- 实时抓包和离线回放均支持过滤
逐层解析链路层到应用层,完整边界检查与健壮性保障:
- 所有 parser 均执行空指针、长度不足、字段越界检查
- IPv4:版本/IHL/total_len 校验、分片处理、扩展选项头边界检查
- IPv6:扩展头链自动遍历(HBH/RH/FH/DOH/AH/ESP),64 层深度上限
- TCP:data_off 范围校验 (
5 ≤ data_off ≤ 15)、options 边界保护 - UDP:length 字段校验 (
≥ 8) 与缓冲区一致性检查 - ICMP:完整类型名称映射(v4 15 种 + v6 13 种)
- DNS:计数上限(256)、循环指针检测(255 跳上限)、非对齐内存安全访问
- HTTP:可打印字符检查防垃圾数据、28 种状态码映射
- 写入:实时抓包同时保存为标准 PCAP 格式(兼容 Wireshark)
- 读取:离线回放,支持 BPF 再过滤
- 文件格式:PCAP 全局头 + 每包时间戳/长度/数据
- 按 7 个协议分类统计包数和字节数
- 每秒自动打印统计面板,含实时速率(pkt/s, B/s)
- 线程安全的固定大小环形队列
- pthread 互斥锁 + 条件变量实现阻塞和超时 pop
- 预分配 4096 个槽位,热路径零 malloc
- 五元组(src/dst IP + port + proto)哈希表索引 TCP 流
- 按 SEQ 排序插入 TCP 段,处理重叠和重传
- TCP 状态机:SYN → ESTABLISHED → FIN
- 超时自动回收空闲流
- 支持 IPv4 和 IPv6 分片重组
- 分片键(src/dst IP + 标识)哈希表
- 超时回收未完成的分片流
- 从 TCP 流中提取完整 HTTP 请求/响应首行
- 解析 HTTP Header 键值对
- 支持 chunked encoding、Content-Length、pipelining
- 识别 TLS ClientHello/ServerHello 握手
- 解析 SNI 扩展提取域名(RFC 6066)
- 双线程架构:capture 线程 → ring buffer → ncurses 主线程
- 实时包列表滚动、协议树逐层展开
- Hex dump 视图(选中包原始字节)
- 显示过滤(关键字匹配 proto/port/IP/MAC)
- 交互式 pcap 保存(补存已有包 + 后续包)
| 协议 | RFC | 等级 | 功能 |
|---|---|---|---|
| Ethernet II | RFC 894 | L2 | MAC 地址解析、EtherType 分发、VLAN 标签(802.1Q) |
| IPv4 | RFC 791 | L3 | 版本/IHL/总长/标识/分片/TTL/协议号/校验和 |
| IPv6 | RFC 8200 | L3 | 版本/TC/流标签/载荷长/下一头/跳限 + 扩展头链遍历 |
| TCP | RFC 793 | L4 | 端口/SEQ/ACK/标志位字串/窗口/校验和/紧急指针 |
| UDP | RFC 768 | L4 | 端口/长度/校验和 |
| ICMP / ICMPv6 | RFC 792 / 4443 | L4 | 类型/代码/校验和/标识/序号 + 15+13 种类型名称 |
| DNS | RFC 1035 | L7 | 查询域名提取、A/AAAA/CNAME 回答解析、压缩指针 |
| HTTP | RFC 7230 | L7 | 请求行(9 方法)、响应行(28 状态码) |
minishark/
├── include/ # 头文件
│ ├── capture.h # 抓包引擎接口
│ ├── common.h # 公共宏、类型、日志
│ ├── filter.h # BPF 过滤器接口
│ ├── http_extract.h # HTTP 报文提取接口
│ ├── ip_reasm.h # IP 分片重组接口
│ ├── pcap_io.h # PCAP 文件读写接口
│ ├── protocol.h # 协议结构体定义 + 解析函数声明
│ ├── ring_buffer.h # 环形缓冲区接口
│ ├── stats.h # 流量统计接口
│ └── tcp_reasm.h # TCP 流重组接口
├── src/ # 源文件
│ ├── main.c # 入口、信号处理、双线程调度
│ ├── capture.c # libpcap 抓包引擎 + 性能统计
│ ├── filter.c # BPF 编译/应用
│ ├── http_extract.c # HTTP 完整报文提取
│ ├── ip_reasm.c # IP 分片重组
│ ├── pcap_io.c # PCAP 文件读写
│ ├── protocol.c # 协议解析(ETH/IP/TCP/UDP/ICMP/DNS/HTTP)
│ ├── ring_buffer.c # 线程安全环形缓冲区
│ ├── stats.c # 实时流量统计
│ └── tcp_reasm.c # TCP 流重组(五元组 + SEQ 排序 + 状态机)
├── tests/ # 测试
│ ├── test_protocol.c # 协议解析单元测试
│ ├── test_tcp_reasm.c # TCP 重组测试
│ ├── test_ip_reasm.c # IP 分片重组测试
│ ├── test_http_extract.c # HTTP 提取测试
│ ├── data/ # 测试用 pcap 数据文件
│ └── README.md # 测试说明
├── Makefile # 构建脚本(含 test 目标)
└── README.md # 本文件
| 天次 | 功能 | 状态 |
|---|---|---|
| Day 1 | 环境搭建、项目骨架、协议头结构体 | ✅ |
| Day 2 | 抓包循环、Ethernet/IP 解析 | ✅ |
| Day 3 | TCP/UDP/ICMP 解析、BPF 过滤 | ✅ |
| Day 4 | DNS/HTTP 解析、流量统计 | ✅ |
| Day 5 | PCAP 文件读写、解析完善与边界修复 | ✅ |
| Day 6 | 环形缓冲区、TCP 流重组基础 | ✅ |
| Day 7 | 多线程架构、TCP 重组完善 | ✅ |
| Day 8 | 性能优化、TLS SNI、ncurses UI 基础 | ✅ |
| Day 9 | ncurses UI 完善:Hex dump/显示过滤/交互保存 | ✅ |
| Day 10 | 测试、文档、收尾 | ✅ |
- 管理员/root 权限:实时抓包必须具有管理员权限(
sudo或以管理员身份运行) - Npcap 兼容模式:Windows 安装 Npcap 时须勾选 "Install in WinPcap API-compatible Mode"
- 离线回放无需 root:
-r模式仅读文件,普通用户即可运行 - BPF 语法:过滤表达式与
tcpdump完全兼容 - 分片 IP 包:IPv4/IPv6 仅解析首分片,非首分片自动跳过
- HTTP 分片:跨 TCP 段的 HTTP 通过
tcp_reasm流重组后可完整提取 - Ctrl+C 停止:抓包循环中按 Ctrl+C 安全终止并自动清理资源
- 日志输出:
[ERROR]红色输出到 stderr,解析结果到 stdout,可独立重定向