docs+test: VPN 测试方案(黑盒+白盒)+ 修正延迟测量方法
- docs/vpn-test-plan.md:黑盒+白盒两方向测试方案。白盒细化:链路五段拆解、 协议/出站选择(Clash API)、接入段 vs 出海段分段 RTT、连接/流量、稳定性 (长跑/Kill switch/GFW 三元组封锁与被动探测/热重载)。含初轮报告:cara 黑盒 15 PASS;吞吐 国内直连 74Mbps vs 国外经隧道 ~10-17Mbps(瓶颈在出海段)。 - scripts/vpn_test.sh:修正延迟测量——经 TUN 代理时 ping/tcp_connect 被隧道本地 应答(2-4ms 假象),改用 TLS 握手(time_appconnect)/ TTFB 作为真实 RTT。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JEHzjEcFzvGwgbxT6Wbt6c
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
# Pangolin VPN 测试方案 + 报告
|
||||
|
||||
> 两个方向:**黑盒**(用户视角,只看输入→输出)+ **白盒**(利用我们对客户端/节点/sing-box
|
||||
> 的完全可见性,拆链路、看协议、做稳定性)。日期 2026-06-22。配套:`scripts/vpn_test.sh`、
|
||||
> 调研见 `docs/vpn-testing-research.md`。
|
||||
|
||||
---
|
||||
|
||||
## 一、测试方向总览
|
||||
|
||||
| | 黑盒 | 白盒 |
|
||||
|---|---|---|
|
||||
| 视角 | 用户视角,不看内部 | 工程视角,看内部链路/协议/状态 |
|
||||
| 目的 | 能不能用、快不快(可用性 + 体验) | 慢在哪、走什么协议、稳不稳(定位 + 稳定性) |
|
||||
| 数据源 | `curl` / `ping` 黑盒探测 | sing-box Clash API、libbox 命令服务、curl 五段拆解、节点侧探测、长跑监控 |
|
||||
| 工具 | `scripts/vpn_test.sh`(已实现) | 待实现:`scripts/vpn_whitebox.sh` + 稳定性长跑 |
|
||||
|
||||
---
|
||||
|
||||
## 二、黑盒测试方案
|
||||
|
||||
**对象:国内外常用站点矩阵**,开/关分流各测一遍,多时段(白天 / 晚高峰 20:00–24:00)。
|
||||
|
||||
### 指标
|
||||
- **连通性**:HTTP 状态码(能否访问)
|
||||
- **延迟 / TTL**:`ping` RTT、`curl time_connect`(TCP+TLS 握手)
|
||||
- **下载速度**:固定大小下载 `speed_download`
|
||||
- **上传速度**:POST 固定大小 `speed_upload`(待补)
|
||||
- **DNS 解析时间**:`curl time_namelookup`
|
||||
- **出口 IP**:是否 = 节点(走隧道)/ 本地(直连)
|
||||
|
||||
### 站点矩阵
|
||||
- **国外(应经隧道)**:google、youtube、github、cloudflare(speed.cloudflare.com)、netflix、openai
|
||||
- **国内(开分流应直连)**:baidu、qq、bilibili、aliyun/清华镜像、taobao
|
||||
- **测速点**:Cloudflare(国外)、清华/阿里镜像(国内,用 `-r 0-N` range 取固定大小)
|
||||
|
||||
### 方法
|
||||
- 先 **裸连基线**(不开 VPN 跑一遍存档)→ 再开 VPN 对比衰减。
|
||||
- 每站取 中位数(多次),记录时段。
|
||||
- 一条命令产报告:`vpn_test.sh`(现覆盖连通/出口/DNS/可达/延迟/下载/IPv6;**待补:上传、ping TTL、站点矩阵扩展、多时段 cron**)。
|
||||
|
||||
---
|
||||
|
||||
## 三、白盒测试方案(重点,更细)
|
||||
|
||||
我们同时掌握**客户端(libbox 命令服务)+ 节点(sing-box Clash API :19090/:19091)+ 配置**,
|
||||
可做黑盒做不到的链路拆解。
|
||||
|
||||
### 3.1 链路五段拆解(每个请求耗时花在哪)
|
||||
用 `curl -w` 拆解一次请求的五个阶段,定位瓶颈在接入段还是出海段:
|
||||
|
||||
| 阶段 | curl 字段 | 含义 |
|
||||
|---|---|---|
|
||||
| DNS 解析 | `time_namelookup` | 域名→IP |
|
||||
| TCP 连接 | `time_connect` | 到隧道/目标的 TCP 握手 |
|
||||
| TLS 握手 | `time_appconnect` | TLS/REALITY 握手完成 |
|
||||
| 首字节 TTFB | `time_starttransfer` | 服务器开始回数据(含出海往返) |
|
||||
| 总时长 | `time_total` | 整体 |
|
||||
|
||||
→ TTFB 高 = 出海段慢;connect 高 = 接入段/节点慢;namelookup 高 = DNS 慢。
|
||||
|
||||
### 3.2 协议与出站选择
|
||||
- 当前激活出站:`reality-out`(VLESS/REALITY,TCP 443)还是 `hy2-out`(Hysteria2,UDP 443)。
|
||||
- `urltest`(auto)各成员探测延迟(决定选谁)。
|
||||
- **数据源**:sing-box Clash API `GET /proxies`(看 `auto` 组的 `now` 与各成员 `history` 延迟);
|
||||
或客户端 libbox 命令服务的 group/outbound 状态。
|
||||
|
||||
### 3.3 分段 RTT(定位瓶颈)
|
||||
- **接入段**:客户端 → 节点 REALITY 端口 TCP RTT(`curl time_connect` 到 `节点:443`)。
|
||||
- **出海段**:在**节点上**直接 `ping`/`curl` 目标站(节点 → 目标 RTT)。
|
||||
- 对比:接入段快 + 出海段慢 → 节点出海链路是瓶颈;反之亦然。
|
||||
|
||||
### 3.4 流量与连接(实时内部状态)
|
||||
- **Clash API `GET /connections`**:活跃连接列表,每连接的 目标 / 上下行字节 / 走哪个出站 / 命中哪条规则 / 建连时长 → 看分流是否如预期(国内直连、国外走代理)。
|
||||
- **Clash API `GET /traffic`(SSE)**:实时上下行速率。
|
||||
- **客户端 libbox**:`writeConnectionEvents` / `writeGroups` / 流量统计(stats EventChannel)。
|
||||
|
||||
### 3.5 sing-box 内部决策日志(debug)
|
||||
- 路由命中:`router: match ... => route(outbound)` → 验证分流规则。
|
||||
- DNS:`dns: exchange/exchanged ...` → 验证 hijack-dns + 解析路径。
|
||||
- 连接生命周期:建连/关闭/错误。
|
||||
- **方法**:配置 `log.level=debug` + `log.output` 落盘读(排障期已用过)。
|
||||
|
||||
### 3.6 路径 MTU / 分片
|
||||
- `ping -D -s <size>` 二分探测路径 MTU,评估 TUN `mtu 9000` 是否导致分片/卡顿
|
||||
(调研:运营商对大包敏感,业界常 clamp 到 1350)。
|
||||
|
||||
### 3.7 节点侧资源(瓶颈定位)
|
||||
- 节点 CPU/内存/带宽(单核 512MB 是硬约束)、sing-box 进程占用、网卡流量。
|
||||
- agent / 控制面健康。
|
||||
|
||||
### 3.8 稳定性测试(白盒重点)
|
||||
- **长跑**:cron 每 1–5 分钟探测(出口 IP + 可达 + 延迟 + 丢包),持续数小时~数天,出趋势曲线。
|
||||
- **掉线 / 重连**:监测 `NEVPNStatus` 变化,记掉线次数、自动重连耗时。
|
||||
- **Kill switch**:强杀扩展进程 / 断节点,验证 `strict_route` 把流量掐断(不裸奔),恢复后能重连。
|
||||
- **GFW 存活**:多日连续可达性;监测**三元组封锁特征**(突然全断 + 120–180s 后恢复);
|
||||
REALITY 端口被动探测(用普通 TLS 客户端连 :443,应表现得像伪装站 www.apple.com)。
|
||||
- **热重载**:节点 agent `SIGHUP` 重载 sing-box 后,客户端是否断流 / 平滑。
|
||||
- **协议切换**:reality-out 不可用时是否切到 hy2-out(urltest 容灾)。
|
||||
|
||||
---
|
||||
|
||||
## 四、当前测试报告(2026-06-22,初轮)
|
||||
|
||||
### 4.1 黑盒(cara,macOS 15.3.2 Intel,白天)
|
||||
`scripts/vpn_test.sh` 全量:**15 PASS / 0 WARN / 0 FAIL**
|
||||
- 连通性:扩展 `activated enabled`、tun `172.19.0.1` ✅
|
||||
- 出口 IP:`103.119.13.48`(= 节点,确实走隧道)✅
|
||||
- DNS:github/google 解析+连通正常 ✅(服务端 `hijack-dns` 已生效)
|
||||
- 国外可达:google/youtube/github/gstatic HTTP 200/204 ✅
|
||||
- 国内可达:baidu/qq ✅
|
||||
- 延迟:**真实 RTT 看 TLS 握手 / TTFB**。实测国外 TLS 握手 **~420–490ms**、TTFB ~600–715ms
|
||||
(节点在洛杉矶,中国→LA→目标多次往返,符合预期)。
|
||||
- IPv6:无泄漏 ✅
|
||||
|
||||
> ⚠️ **延迟测量教训(重要)**:经 TUN 代理时,`ping` 和 `curl time_connect` 会被隧道的
|
||||
> 本地协议栈**就地应答**(0.3ms / 2-4ms 的假象),**不反映真实到目标的 RTT**。初轮误把
|
||||
> `time_connect` 当延迟(2-4ms),实为本地值。真实延迟必须看 **TLS 握手(`time_appconnect`)**
|
||||
> 或 **TTFB(`time_starttransfer`)**,或在 **VPN 全关后 ping 节点**测直连 RTT。`vpn_test.sh`
|
||||
> 已据此修正。
|
||||
|
||||
### 4.2 吞吐对比(关键)
|
||||
| 路径 | 速度 | 说明 |
|
||||
|---|---|---|
|
||||
| **国外(经隧道)** Cloudflare 10MB | **~10–17 Mbps**(多次波动:7.66 / 10.6 / 17.4) | 走 REALITY→节点→出海 |
|
||||
| **国内(直连)** 清华镜像 10MB | **74.28 Mbps** | geoip-cn 命中 → 直连,不经隧道 |
|
||||
| 国内 阿里云镜像 | 未测到(URL 失效) | 待换有效测速 URL |
|
||||
|
||||
**结论:**
|
||||
1. **分流生效**:国内直连(74 Mbps)远快于国外经隧道(~10-17),说明 geoip-cn 直连正常。
|
||||
2. **瓶颈在出海段**:国外吞吐受限于隧道——单核 512MB 联调节点 + 出海带宽 + 可能晚高峰。不是客户端/隧道软件问题。
|
||||
3. **波动大**(7.66→17.4):需按调研文档**多时段、多次取中位数**,单点不可靠。
|
||||
|
||||
### 4.3 待补
|
||||
- 黑盒:上传速度、ping TTL、站点矩阵扩展、**晚高峰复测**、裸连基线对比。
|
||||
- 白盒:Clash API 拉连接/出站/urltest 延迟、五段拆解、分段 RTT(接入 vs 出海)、稳定性长跑、Kill switch、GFW 存活。
|
||||
|
||||
---
|
||||
|
||||
## 五、工具落地计划
|
||||
1. **扩展 `scripts/vpn_test.sh`(黑盒)**:加 上传测速 / ping TTL / 站点矩阵 / `--baseline` 基线 / 多时段 cron。
|
||||
2. **新增 `scripts/vpn_whitebox.sh`(白盒)**:读节点 Clash API(连接/出站/延迟)+ curl 五段拆解 + 接入/出海分段 RTT + 路径 MTU。
|
||||
3. **新增稳定性长跑**:cron 周期探测落 CSV,出趋势;Kill switch / 重连 / GFW 存活脚本。
|
||||
+14
-5
@@ -100,12 +100,21 @@ for u in "${DOMESTIC[@]}"; do
|
||||
else W "$host" "不可达(分流/DNS 异常?)"; fi
|
||||
done
|
||||
|
||||
# ── 6. 延迟(连接握手耗时)────────────────────────────────────────────
|
||||
H "6. 延迟"
|
||||
for u in "https://$NODE_IP:8080" "https://www.gstatic.com/generate_204"; do
|
||||
tc=$(cget -k -o /dev/null -w "%{time_connect}" "$u" 2>/dev/null)
|
||||
[ -n "$tc" ] && [ "$tc" != "0.000000" ] && P "connect $u" "${tc}s" || W "connect $u" "无响应/超时"
|
||||
# ── 6. 延迟(真实 RTT)────────────────────────────────────────────────
|
||||
# ⚠️ 经 TUN 代理时 tcp_connect / ping 会被隧道本地应答(假的几 ms),不能当真实 RTT。
|
||||
# 真实延迟看 TLS 握手(time_appconnect,必须真往返到目标)与 TTFB(time_starttransfer)。
|
||||
H "6. 延迟(真实 RTT:TLS 握手 / TTFB;tcp_connect 经隧道为本地值仅供对照)"
|
||||
for u in "https://www.google.com/generate_204" "https://www.gstatic.com/generate_204"; do
|
||||
read -r tcp tls ttfb < <(cget -o /dev/null -w "%{time_connect} %{time_appconnect} %{time_starttransfer}" "$u" 2>/dev/null || echo "0 0 0")
|
||||
host=$(echo "$u" | sed -E 's#https?://([^/]+).*#\1#')
|
||||
if awk "BEGIN{exit !($tls>0)}" 2>/dev/null; then
|
||||
tlsms=$(awk "BEGIN{printf \"%.0f\", $tls*1000}"); ttfbms=$(awk "BEGIN{printf \"%.0f\", $ttfb*1000}"); tcpms=$(awk "BEGIN{printf \"%.0f\", $tcp*1000}")
|
||||
if [ "$tlsms" -lt 500 ] 2>/dev/null; then P "$host RTT" "TLS握手 ${tlsms}ms, TTFB ${ttfbms}ms (tcp_connect ${tcpms}ms=本地)"
|
||||
elif [ "$tlsms" -lt 1000 ] 2>/dev/null; then W "$host RTT" "TLS握手 ${tlsms}ms 偏高, TTFB ${ttfbms}ms"
|
||||
else F "$host RTT" "TLS握手 ${tlsms}ms 过高, TTFB ${ttfbms}ms"; fi
|
||||
else F "$host RTT" "无响应/超时"; fi
|
||||
done
|
||||
echo " ${B}提示${N}: 真实到节点的直连 RTT 请在【VPN 全关】后 ping 节点;开着 TUN ping 是本地假象。"
|
||||
|
||||
# ── 7. 吞吐(下载速度)────────────────────────────────────────────────
|
||||
if [ "$QUICK" = 0 ]; then
|
||||
|
||||
Reference in New Issue
Block a user