allanjoshuaf/dpi-probe
GitHub: allanjoshuaf/dpi-probe
一个用于检测和指纹识别网络路径上 DPI 流量干扰的 Python 工具包,通过多维探测信号和置信度评分判断是否存在审查或中间人设备。
Stars: 0 | Forks: 0
# dpi-probe
`dpi-probe` 是一个 Python 工具,用于检测和指纹识别本地网络路径上的流量干扰。
它会探测 TLS SNI、目标 IP、HTTP Host 头、格式错误的 TLS payload、TTL 行为或 TCP 重置时序是否正在被 DPI/中间人设备过滤、丢弃、注入或修改。
## 测试内容
- 端口 443 上的 TCP 可达性
- 端口 80 上的纯 HTTP 行为
- 使用精心构造的 ClientHello 数据包进行 TLS SNI 过滤检测
- 干净域名与被封禁域名的差异化行为
- TTL 跳数行为和 ICMP 抑制模式
- 与基准 RTT 对比的 RST/响应时序
- 格式错误的 TLS ClientHello 响应
- 包含中位数、p95、方差和一致性的重复采样
- 带有每个信号置信度水平的 JSON 报告
## 前置条件
- Python 3.11+
- 对于 `--pcap` 模式:需要带有 tshark 的 Wireshark
从 https://www.wireshark.org/download.html 安装 Wireshark,并在安装过程中勾选“Install TShark”和“Install Npcap”。
查找你的活动网络接口:
```
py -c "from src import pcap; [print(i) for i in pcap.list_interfaces()]"
```
然后使用 `--pcap-interface N` 传递它。
## 使用方法
```
# 自动检测本地流量干扰
py main.py
# 探测特定目标
py main.py 1.1.1.1
# 每个 probe 重复 3 次
py main.py 1.1.1.1 --samples 3
# 标记网络状况
py main.py 1.1.1.1 --samples 3 --profile no-vpn
py main.py 1.1.1.1 --samples 3 --profile adguard
py main.py 1.1.1.1 --samples 3 --profile reality
# 从 targets.json 探测所有已配置的目标
py main.py --multi --samples 3 --profile no-vpn
# 比较两个报告
py main.py --compare reports/report_A.json reports/report_B.json
# 显示版本
py main.py --version
```
定向探测会将 JSON 报告保存在 `reports/` 目录中。
## 配置说明
目标和域名列表从 `targets.json` 加载。
```
{
"targets": [
{"ip": "1.1.1.1", "name": "Cloudflare DNS"},
{"ip": "8.8.8.8", "name": "Google DNS"},
{"ip": "9.9.9.9", "name": "Quad9 DNS"}
],
"domains": {
"blocked": ["instagram.com", "facebook.com", "twitter.com", "youtube.com", "x.com"],
"clean": ["google.com", "github.com", "cloudflare.com", "yandex.ru", "rutube.ru"]
}
}
```
## 输出示例
```
==================================================
DPI PROBE REPORT
Target : 1.1.1.1
Timestamp : 2026-05-23T12:21:58Z
DPI detected : YES
Confidence : HIGH
Score : 9/10
Findings :
→ SNI filtering observed for: instagram.com, facebook.com, twitter.com, x.com
→ TTL/ICMP behavior consistent with suppression at hops [1, 2, 3, 5, 8]
→ RST timing consistent with closer responder - 0.46x baseline
→ Malformed TLS responses faster than clean SNI baseline - timing consistent with middlebox TLS parser
```
该评分在设计上是保守的。每个信号都会单独加权,并报告其各自的置信度水平。
## 实地结果:受限网络路径
这些是在一条受限网络路径上的真实观察结果。结果特定于该路径,不应将其推广到其他 ISP 或国家/地区。
### PCAP 抓包分析
在探测运行期间使用 `--pcap` 标志捕获。需要 Wireshark/tshark。
| 指标 | Tele2 4G no-vpn | VLESS Reality |
|---|---|---|
| 总数据包数 | 716 | 806 |
| 重传次数 | 129 | 0 |
| RST 数据包 | 24 | 0 |
| TLS 警报 | 36 | 52 |
| 主要 TTL | 55 (9 跳) | 64 (本地隧道) |
| 平均包间隔时间 | 192ms | 63ms |
| 平均数据包大小 | 101.7B | 65.5B |
在 no-vpn 下:129 次重传证实了静默丢弃行为;被阻断的数据包触发了 TCP 重传退避。在 VLESS Reality 下:零重传,所有数据包均通过隧道到达目的地。
### SNI 过滤
针对 `1.1.1.1` (Cloudflare) 和 `8.8.8.8` (Google DNS) 进行测试,无 VPN:
| SNI | 1.1.1.1 | 8.8.8.8 | 观察结果 |
|---|---|---|---|
| google.com | tls_alert | tls_alert | PASS |
| github.com | tls_alert | tls_alert | PASS |
| cloudflare.com | tls_alert | tls_alert | PASS |
| yandex.ru | tls_alert | tls_alert | PASS |
| rutube.ru | tls_alert | tls_alert | PASS |
| instagram.com | silent_drop | silent_drop | BLOCKED |
| facebook.com | silent_drop | silent_drop | BLOCKED |
| twitter.com | silent_drop | silent_drop | BLOCKED |
| x.com | silent_drop | silent_drop | BLOCKED |
| youtube.com | tls_alert | silent_drop | PARTIAL |
在被阻断的域名上观察到了 SNI 过滤。干净域名则一致通过。`youtube.com` 的行为在不同目标之间有所不同,这表明存在 SNI + 目标 IP 的关联性。
### TTL 跳数分析
| TTL | 1.1.1.1 | 8.8.8.8 |
|---|---|---|
| 1–8 | timeout | timeout |
| 13 | connected | timeout |
| 21 | connected | connected |
| 64 | connected | connected |
在第 1 跳和第 13 跳之间未观察到 ICMP TTL 超时响应。这与网络路径上的 ICMP 抑制一致,尽管单凭这一点并不能作为确凿证据。
### RST 时序
| 目标 | 基准 RTT | RST 时序 | 比率 | 观察结果 |
|---|---|---|---|---|
| 1.1.1.1 | ~21ms | ~9ms | 0.46x | 与较近的响应者一致 |
| 8.8.8.8 | ~22ms | ~24ms | 1.09x | 无异常 |
### 格式错误的 TLS ClientHello
| 变体 | 响应 | 警报代码 | RTT 中位数 |
|---|---|---|---|
| wrong_version | tls_alert | 0x28 | 13ms |
| empty_ciphers | tls_alert | 0x32 | 9ms |
| oversized_sni | tls_alert | 0x32 | 8ms |
| truncated | tls_alert | 0x32 | 7ms |
| duplicate_sni | tls_alert | 0x32 | 9ms |
在此网络路径上,这些响应的到达速度快于干净的 SNI 基准,这与中间存在 TLS 解析器的情况相符。
### VPN 对比
| 条件 | SNI 丢弃 | RST 比率 | DPI 信号 | 备注 |
|---|---|---|---|---|
| 无 VPN | 4/5 | 0.46x | 是 | 观察到了过滤和时序异常 |
| AdGuard VPN | 0/5 | ~0.45x | 是 | SNI 被隐藏,时序异常仍然存在 |
| VLESS Reality | 0/5 | 26–394x | 否 | 无可观察信号 |
AdGuard 掩盖了 SNI 丢弃,但时序异常依然存在。在此测试环境中,VLESS Reality 消除了探测器可检测到的 DPI 信号。
## 方法论
`dpi-probe` 将原始观察结果与解释分离开来。
- 在被封禁的 SNI 上出现 `silent_drop`,同时干净域名能正常响应,这暗示存在基于 SNI 的过滤。
- RST/响应时序明显低于基准 RTT,可能表明路径上存在距离更近的响应者。
- 缺失 ICMP TTL 超时响应单独被视为一个弱信号,但在组合出现时信号更强。
- 格式错误的 TLS 响应在评分前会与干净的 SNI 基准时序进行比较。
- 每个信号都报告了其自身的置信度水平。总分汇总了独立加权的信号。
## 局限性
- 尚无自动 PCAP 抓包功能。需与 Wireshark 或 `tcpdump` 并行运行以获取更有力的证据。
- 尚未捕获响应 TTL。基于 TTL 的归因将显著增强时序信号。
- 伪造的 ClientHello 数据包虽然逼真,但与 Chrome/Firefox 的指纹并不完全相同。
- 仅凭 TTL 超时无法证明存在 DPI。
- 在没有数据包级别验证的情况下,基于时序的归因是概率性的。
- 域名封锁列表会随时间变化,应在 `targets.json` 中进行更新。
## 安全提示
此工具生成的流量可能会指向在某些国家或网络中被封锁或视为敏感的域名。
请仅在您了解法律、运营和个人风险的情况下使用它。
报告和抓包数据可能会暴露您的 IP 地址、ISP、测试的域名、时间戳和网络行为。在公开分享之前请仔细检查。
## 路线图
### 阶段 1 - 核心探测
- [x] TCP 443 可达性测试
- [x] 纯 HTTP 行为测试
- [x] SNI 指纹识别
- [x] TTL 跳数分析
- [x] RST 时序指纹识别
- [x] 格式错误的 TLS ClientHello 探测
- [x] JSON 报告输出
### 阶段 2 - 可靠性
- [x] 可配置的采样数量
- [x] 中位数、p95、方差、超时率
- [x] 基于配置的干净/封锁域名列表
- [x] 每个信号的置信度水平
- [x] 将观察结果与解释分离
- [x] 一次运行中的多目标探测
- [x] 稳定的 JSON schema
### 阶段 3 - DPI 分类
- [x] 基于 IP 的封锁分类
- [x] HTTP Host 头过滤检测
- [x] SNI + 目标 IP 关联检测
- [x] 对比模式 - `--compare` 两份报告
- [x] 配置文件标记 - `--profile`
- [x] 基于样本数量的可靠性指标
### 阶段 4 - 指纹识别
- [x] 捕获响应 TTL
- [x] 比较响应 TTL 与基准 TTL
- [x] 可选的 PCAP 导出
- [x] Wireshark/tshark 分析助手
### 阶段 5 - 易用性
- [ ] `--quick`, `--full`, `--stealth` 模式
- [ ] 人类可读的文本报告
- [x] 带有版本控制的稳定 JSON schema
- [ ] PyPI 包
[x] anonymize
## 技术栈
- Python 3.11+
- 仅使用标准库 - 无外部依赖
- 标准库 TCP socket,构造的 TLS payload
## 作者
由 [allanjoshuaf](https://github.com/allanjoshuaf) 构建
标签:DPI检测, Homebrew安装, Python, TLS分析, 情报分析, 数据包构造, 数据泄露防护, 无后门, 网络审查, 网络探测, 网络诊断