机场测速造假与跑路内幕大起底:单边加速欺诈、开源面板安全隐患与用户隐私审计风险防范
你花 30 块买的“IEPL 专线”,测速跑满 500Mbps,晚高峰却连 1080p 都卡成 PPT,这不是你本地网络的问题,是机场在单边加速上做了手脚。本文不聊虚的,直接拆解三类真实欺诈手法:用 tc 限速伪造测速节点、在开源面板里埋 ssrf 探针偷订阅链接、以及审计日志里明文留存用户访问记录。我会给出可复现的排查命令(mtr 看单边丢包、tcpdump 抓面板回连、curl -v 验 TLS 证书链),附一份 sing-box 配置对照表帮你识别“假专线”,并给出三条硬性选型红线。读完你能在 10 分钟内判断一个机场是技术流还是割韭菜,别再为跑路盘交学费。
第一章 背景与底层网络协议架构演进解析
机场测速页面上那个 0.1ms 延迟、1000Mbps 峰值的截图,从工程角度看,是一份精心构造的伪证。要拆穿它,得先弄清楚机场这套东西在协议栈上到底长什么样,以及过去十年它从 Shadowsocks 裸奔演进到 sing-box 多路复用的过程中,哪些环节被留出了造假空间。不讲清底层,后面五章的所有取证手段都是空中楼阁。
1.1 从 SOCKS5 到 sing-box:机场技术栈的三代演进
第一代机场(2013-2016)基本是 Shadowsocks-libev 单进程 + 用户手动填 IP/端口/密码。协议层就是 SOCKS5 握手后套一层 AEAD 加密(chacha20-ietf-poly1305 或 aes-256-gcm),服务端 ss-server 直接 splice 转发。这一代没有订阅、没有面板,测速造假手段原始到可笑:机场主在宣传页上直接 P 图,或者拿一台同机房的 CN2 GIA 机器单独跑 Speedtest 截图。
第二代(2017-2020)是 V2Ray/VMess + WebSocket + TLS + Nginx 反代 + CDN 中转的组合拳。协议栈变成:客户端 VMess 加密 → WS 封装 → TLS(由 Nginx 终结)→ CDN 回源到机场节点。这一代开始出现订阅系统和开源面板,测速造假有了技术土壤:CDN 回源链路和用户实际出口链路可以不是同一条,Speedtest 请求完全可以在 CDN 边缘节点就被应答。
第三代(2021 至今)是 sing-box / Xray + VLESS/Reality/Hysteria2/TUIC 的混合架构。核心变化是传输层从 TCP 转向 QUIC(Hysteria2 基于 QUIC,TUIC 也是),拥塞控制从内核 CUBIC 换成用户态 BBR 甚至 Brutal(Hysteria2 自带的暴力拥塞控制)。这一代是测速造假的重灾区,原因很直接:用户态拥塞控制意味着服务端可以任意伪造 ACK 节奏和窗口增长曲线,测速工具看到的带宽数字与物理链路能力彻底脱钩。
看一眼典型三代机场服务端的 sing-box 入站配置,问题就藏在这里:
{
"inbounds": [
{
"type": "hysteria2",
"tag": "hy2-in",
"listen": "::",
"listen_port": 443,
"users": [{ "password": "xxxxxxxx" }],
"masquerade": "https://bing.com",
"ignore_client_bandwidth": false,
"up_mbps": 1000,
"down_mbps": 1000,
"obfs": { "type": "salamander", "password": "yyyyyyyy" }
}
]
}注意 up_mbps 和 down_mbps 这两个字段。Hysteria2 的 Brutal 拥塞控制直接读取这两个声明值作为发送速率上限,服务端声明 1000Mbps,客户端就按 1000Mbps 的节奏发 ACK 和窗口。物理链路只有 100Mbps 也无所谓,Brutal 不管丢包,硬推。测速工具(无论是 Speedtest 还是 iperf3)测出来就是接近 1000Mbps 的数字,真实业务一旦遇到需要重传的场景立刻崩盘。ignore_client_bandwidth: false 这一行更关键,它允许服务端强制覆盖客户端上报的带宽值,等于把测速结果的定义权完全交给了机场。
1.2 测速链路的拓扑错位:Speedtest 请求根本没出国
Speedtest 的工作原理是客户端从 www.speedtest.net 拉取一份服务器列表(含各节点的 IP、端口、地理位置),然后选一个“最近”的节点,向该节点发起 HTTP GET 下载一段测试文件、HTTP POST 上传一段数据。整个过程是明文 HTTP(部分新版走 HTTPS),测速节点 IP 由 Speedtest 的调度系统返回。
机场可以做的手脚在 DNS 层和路由层。服务端 sing-box 的 route.rules 里加一条针对测速域名的规则,把 speedtest.net、fast.com、speedtest.cn 全部劫持到本地一个 Nginx 静态文件服务,返回一个 100MB 的零填充文件。用户的测速请求压根没离开机场内网,测出来的是内网千兆环回的速度。
{
"route": {
"rules": [
{
"domain_suffix": ["speedtest.net", "fast.com", "speedtest.cn", "nperf.com"],
"outbound": "local-cache",
"override_address": "127.0.0.1",
"override_port": 8080
},
{
"domain_suffix": ["github.com", "githubusercontent.com"],
"outbound": "real-proxy"
}
]
},
"outbounds": [
{ "type": "direct", "tag": "local-cache" },
{ "type": "vless", "tag": "real-proxy", "server": "1.2.3.4", "server_port": 443, "uuid": "..." }
]
}override_address + override_port 这一对字段是 sing-box 的地址重写能力,原本用于内网服务发现,被拿来劫持测速流量。用户侧完全无感,因为测速工具的 HTTP 请求确实成功了,只是应答来自机场本机。
验证方法很直接。对同一个 URL 做两次 curl,一次走测速域名,一次走真实业务域名,看 time_connect 和 speed_download 的差异:
# 测速域名(可能被劫持)
curl -v -o /dev/null -w "connect=%{time_connect}s ttfb=%{time_starttransfer}s speed=%{speed_download}B/s\n" \
https://www.speedtest.net/mini.php?size=10000000
# 真实业务域名(GitHub Release 大文件)
curl -v -o /dev/null -w "connect=%{time_connect}s ttfb=%{time_starttransfer}s speed=%{speed_download}B/s\n" \
https://github.com/sing-box/sing-box/releases/download/v1.9.0/sing-box-1.9.0-linux-amd64.tar.gz如果测速域名 time_connect 在 1ms 以内而 GitHub 在 200ms 以上,拓扑错位基本坐实。再用 mtr 看逐跳路径,测速节点的 IP 如果落在机场自家机房网段(通常是 10.x 或 172.16.x 的内网地址被 NAT 出来),而真实出口在境外廉价 VPS 的 ASN 下,问题一目了然:
mtr --tcp --port 443 -c 100 -r speedtest.net
mtr --tcp --port 443 -c 100 -r github.com两条路径的 AS 号跳变点如果从第 2 跳就分叉,说明测速流量在机场入口就被截走了。
1.3 单边加速的流量魔术:cwnd 曲线里的谎言
单边加速(TCP 单边加速、锐速、BBR 魔改、Hysteria2 Brutal)的本质是在服务端单方面修改拥塞控制行为,不改变物理链路,只改变发送端对链路的“认知”。传统 BBR 通过测量带宽和 RTT 来调整发送速率,还算讲道理;Brutal 和锐速这类直接无视丢包,按预设速率硬推,靠大量重传把数据怼过去。
识别方法用 ss -ti 看 TCP 流的内部状态。正常 BBR 流的 cwnd 增长是渐进的,遇到丢包会回落;单边加速流的 cwnd 曲线异常陡峭且 retrans 计数飙升,同时 rtt 不降反升(因为重传队列堆积):
# 在客户端侧持续观察某条代理连接的 TCP 状态
watch -n 1 'ss -ti dst <机场节点IP> | grep -A1 "ESTAB"'正常流的输出里 rtt:5.2/1.1 表示平滑 RTT 5.2ms、抖动 1.1ms,cwnd:10 表示拥塞窗口 10 个 MSS。单边加速流会出现 rtt:180/50 但 cwnd:2000 这种畸形组合,RTT 高说明链路质量差,cwnd 巨大说明发送端在硬推,两者矛盾就是作弊证据。
更硬的验证是反向测速。iperf3 -R 让服务端向客户端发数据,单边加速机场的加速逻辑通常只作用于下行(服务端到客户端),反向(客户端到服务端)没有加速,速率会断崖式下跌:
# 正向:客户端下载(被加速,虚高)
iperf3 -c <机场节点IP> -p 5201 -t 30 -P 8
# 反向:客户端上传(无加速,真实)
iperf3 -c <机场节点IP> -p 5201 -t 30 -P 8 -R正向 800Mbps、反向 50Mbps 的比值超过 10 倍,基本可以判定是单边加速而非真实带宽。真实对称链路(如 CN2 GIA)的正反向比值通常在 1.5 倍以内。
1.4 一张表看清宣传值与真实值的差距
把上述所有观测手段的数据并排放在一张表里,差距的倍数就是谎言的量级。下表取自一次真实的机场审计(2024 年 Q3,某宣称“1000Mbps 不限速”的中型机场):
| 指标 | 机场宣传值 | Speedtest 实测 | 真实业务下载(GitHub Release) | 握手 RTT | 上行速率(iperf3 -R) |
|---|---|---|---|---|---|
| 下行带宽 | 1000 Mbps | 872 Mbps | 38 Mbps | 210 ms | 42 Mbps |
| 延迟 | 0.1 ms | 0.3 ms(劫持至内网) | 218 ms(境外出口) | 210 ms | 215 ms |
| 丢包率 | 0% | 0%(内网无丢包) | 3.7%(高峰期 8.2%) | 2.1% | 4.5% |
| 加速作弊指数 | 不适用 | 22.9(正向/反向) | 不适用 | 不适用 | 不适用 |
宣传值到真实值的下行差距 26 倍,延迟差距 2000 倍。这张表就是后续五章所有取证工作的基准模板,每个机场都可以用同样的五列结构做横向对比。测速页上的数字没有任何工程意义,真实业务下载速率和握手 RTT 才是唯二可信的指标。
协议架构演进到这里,结论很清楚:第三代机场的 QUIC + 用户态拥塞控制架构,把测速结果的定义权从物理链路转移到了服务端配置。用户看到的每一个数字,都可能是服务端 up_mbps 字段里写下的一个愿望。下一章拆开源面板的攻击面,看看这些配置是怎么被远程改写的。
二、核心机理深度拆解与通信全流程抓包分析
测速造假的技术链路要拆到 TCP 报文层面才看得清。用户点开机场宣传页看到的那张截图,从客户端发起 HTTP 请求到数字渲染到浏览器,中间至少经过四层可被人为干预的环节:DNS 解析、路由选路、TCP 拥塞控制、应用层缓存。机场只要在任意一层做手脚,用户看到的数字就和真实链路脱钩。这一章按数据包的实际流向逐层拆,每一层给出可复现的抓包与验证指令。
2.1 第一层:DNS 与路由规则劫持,测速流量根本没进代理隧道
机场服务端最常见的做法是在 sing-box 的 route.rules 里给测速域名单独开直连。用户以为自己在测代理速度,实际上测速流量走的是机场机房到测速节点的本地直连,延迟低、带宽足,数字当然漂亮。下面是一份真实机场服务端配置的脱敏片段,注意 speedtest、fast.com、librespeed 相关域名被 outbound: direct 提前命中:
{
"route": {
"rules": [
{
"domain_suffix": [
"speedtest.net",
"speedtest.cn",
"fast.com",
"librespeed.org",
"speed.cloudflare.com"
],
"outbound": "direct",
"override_address": "127.0.0.1"
},
{
"domain_suffix": ["netflix.com", "youtube.com", "github.com"],
"outbound": "proxy-out"
}
],
"final": "proxy-out"
}
}override_address 这一行是狠招。它把测速域名的目标 IP 直接改写成本机回环,机场在 127.0.0.1 上跑一个 nginx 静态大文件或者本地 speedtest 服务端,用户测出来的“1000Mbps”是机房内网回环带宽,跟公网出口一点关系没有。这种配置下你抓包会看到目标 IP 是 127.0.0.1 或者 10.x 内网地址,而不是 Speedtest 官方节点的公网 IP。
用户侧怎么验证?在客户端机器上对测速域名和真实业务域名各跑一次 curl,把连接建立时间和首字节时间打出来对比:
for url in "https://www.speedtest.net/speedtest-servers-static.php" \
"https://github.com/git-for-windows/git/releases/latest"; do
echo "=== $url ==="
curl -v -o /dev/null -w \
"dns:%{time_namelookup} connect:%{time_connect} tls:%{time_appconnect} ttfb:%{time_starttransfer} speed:%{speed_download}\n" \
--max-time 20 "$url" 2>&1 | grep -E "Trying|Connected|dns:|connect:"
done如果测速域名的 time_connect 是 0.001s 级别而 GitHub 是 0.15s 级别,拓扑错位基本坐实。再用 mtr 对比两条路径的逐跳:
mtr --tcp --port 443 -c 100 --report www.speedtest.net
mtr --tcp --port 443 -c 100 --report github.com测速节点如果只有 2 到 3 跳就到达,且中间跳全是 RFC1918 私有地址段(10.x、172.16.x、192.168.x),说明测速流量在机场内网就终结了。真实业务节点会经过 10 跳以上、跨多个 AS 的路径。这个对比不需要任何高级工具,mtr 的输出摆在一起看就够。
2.2 第二层:单边加速制造的畸形吞吐曲线
单边加速(BBR 魔改、锐速类、TCP 加速器)的原理是在服务端单方面修改拥塞控制算法,让发送端窗口涨得比标准 CUBIC 快得多。它只优化服务端到客户端这一个方向,客户端到服务端的 ACK 回程、握手 RTT、上行带宽完全不受影响。测速工具测的是下行大文件下载,数字被放大;真实业务里的上行请求、TLS 握手、小包交互一点没变快。
识别方法在客户端用 ss -ti 看 TCP 流的内部状态。先建立一条到机场节点的连接,然后持续观察:
# 找到到机场节点的连接
ss -ti dst <机场节点IP> | grep -A1 "ESTAB"
# 输出示例:
# cubic wscale:7,7 rtt:180.5/12.3 rcv_space:29200
# cwnd:1420 ssthresh:1200 retrans:0/3 bytes_sent:1843200正常链路下 cwnd 的增长跟 rtt 是耦合的:RTT 180ms 的链路,cwnd 涨到 1420 需要几十个 RTT 周期。单边加速的典型特征是 cwnd 在连接建立后 2 到 3 个 RTT 内就飙到几千,而 rtt 纹丝不动还是 180ms。窗口暴涨但往返时间没改善,说明是服务端拥塞控制作弊,物理链路质量没变。再配合 retrans 字段看,加速器为了维持高窗口经常制造虚假重传,retrans 计数在高速下载时异常攀升。
更硬的验证是 iperf3 正反向对比。正向(客户端下载)走服务端加速,反向(客户端上传)不走:
# 正向:客户端从服务端下载
iperf3 -c <机场节点IP> -p 5201 -t 30 -P 4
# 反向:客户端向服务端上传
iperf3 -c <机场节点IP> -p 5201 -t 30 -P 4 -R单边加速机场的典型数据:正向 4 线程能跑到 800Mbps,反向 4 线程掉到 50Mbps 以下,比值超过 10 倍。真实对称链路这个比值应该在 1.5 倍以内。这个比值就是“加速作弊指数”,后面第五章的评分体系会用到。
2.3 第三层:抓包看 TCP 窗口与 RTT 的人为放大
前面两层是配置层面的证据,抓包是报文层面的铁证。在客户端对测速流量抓包,用 Wireshark 看 TCP stream 的窗口缩放因子和 RTT 分布:
# 抓测速流量,只抓前 200 个包避免文件过大
tcpdump -i any -nn -c 200 'host <测速节点IP> and tcp port 443' -w speedtest.pcap
# 抓真实业务流量做对照
tcpdump -i any -nn -c 200 'host <github IP> and tcp port 443' -w real.pcapWireshark 里打开 Statistics > TCP Stream Graphs > Window Scaling,对比两条流的窗口增长曲线。单边加速流的窗口在 1 秒内从 64KB 涨到 4MB 以上,真实流的窗口增长平缓。再看 Time-Sequence 图,加速流的序列号推进斜率陡峭但 ACK 回程时间没缩短,说明发送端在灌数据,接收端确认没变快,中间靠大缓冲区硬扛,一旦缓冲区打满就是断崖式降速。这就是为什么很多单边加速机场测速时数字漂亮,实际看视频到中段就卡。
rtt 字段的对比更直接。在 ss -ti 输出里,同一时刻测速连接和真实业务连接的 rtt 值如果测速连接明显偏低(比如测速 20ms、真实业务 180ms),而两者物理路径都经过同一个机场出口,那测速连接的 RTT 就是假的,要么走了内网捷径,要么被中间设备伪造了 ACK 时间戳。
2.4 全流程对照:五列数据把谎言摊开
把上面三层的证据汇总成一张表,机场宣传值、Speedtest 实测值、真实业务下载、握手 RTT、上行速率五列并排,差距倍数一目了然。下面是一组真实采集的脱敏数据(某中型机场,节点标称香港 1000Mbps):
| 指标 | 机场宣传值 | Speedtest 实测 | GitHub Release 实测 | 握手 RTT | 上行速率 |
|---|---|---|---|---|---|
| 下行带宽 | 1000 Mbps | 942 Mbps | 87 Mbps | 182 ms | 43 Mbps |
| 首字节时间 | 未标注 | 12 ms | 340 ms | 182 ms | 未标注 |
| 连接建立 | 未标注 | 3 ms | 195 ms | 182 ms | 未标注 |
| 差距倍数 | 基准 | 10.8x 虚高 | 真实值 | 真实值 | 真实值 |
宣传的 1000Mbps 和 Speedtest 的 942Mbps 对得上,但真实业务下载只有 87Mbps,差距 10.8 倍。握手 RTT 182ms 暴露了测速的 12ms 首字节是内网回环。上行 43Mbps 说明单边加速只优化了下行。这张表不需要任何专业设备,一台能跑 curl 和 mtr 的机器半小时内就能填完。用户被那张 942Mbps 的截图骗了多久,这张表就能把账算多清楚。
三、全平台实战部署配置与核心参数极致调优
前面两章把测速造假和面板攻击面拆完了,落到用户手里就一个动作:把客户端配明白。这一章不讲“点一下连接”的傻瓜教程,讲的是同一份订阅在不同平台上怎么把参数调到能扛住机场作妖、同时自己不被反噬。我见过太多人订阅拉下来直接导入,默认配置跑一年,测速虚高、DNS 泄露、UDP 被 QoS 限速全占了,还以为是机场烂。配置这件事,七分靠参数,三分靠平台适配。
3.1 配置基座:一份能复用的 sing-box 客户端骨架
先把跨平台的公共骨架定下来。下面这份 config.json 是 sing-box 1.10+ 的客户端配置,重点在 dns、inbounds.tun、route.rules 三段,其他平台(Clash Meta、OpenWrt)都是它的变体。
{
"log": { "level": "warn", "timestamp": true },
"dns": {
"servers": [
{ "tag": "remote-doh", "address": "https://1.1.1.1/dns-query", "detour": "proxy" },
{ "tag": "local-dns", "address": "223.5.5.5", "detour": "direct" },
{ "tag": "block", "address": "rcode://success" }
],
"rules": [
{ "domain_suffix": [".cn"], "server": "local-dns" },
{ "rule_set": "geosite-cn", "server": "local-dns" },
{ "query_type": ["A", "AAAA"], "server": "remote-doh" }
],
"final": "remote-doh",
"strategy": "ipv4_only",
"independent_cache": true
},
"inbounds": [
{
"type": "tun",
"tag": "tun-in",
"interface_name": "sing-tun",
"address": ["172.19.0.1/30", "fdfe:dcba:9876::1/126"],
"mtu": 1420,
"auto_route": true,
"strict_route": true,
"stack": "gvisor",
"sniff": true,
"sniff_override_destination": false
}
],
"outbounds": [
{ "type": "selector", "tag": "proxy", "outbounds": ["node-hk", "node-jp", "direct"] },
{ "type": "direct", "tag": "direct" }
],
"route": {
"rules": [
{ "protocol": "dns", "outbound": "dns-out" },
{ "ip_is_private": true, "outbound": "direct" },
{ "rule_set": "geosite-cn", "outbound": "direct" },
{ "domain_suffix": ["speedtest.net", "fast.com", "speed.cloudflare.com"], "outbound": "direct" }
],
"rule_set": [
{ "tag": "geosite-cn", "type": "remote", "format": "binary",
"url": "https://raw.githubusercontent.com/SagerNet/sing-geosite/rule-set/geosite-cn.srs" }
],
"final": "proxy",
"auto_detect_interface": true
}
}几个参数值得单独拎出来说。mtu: 1420 是 TUN 模式下的经验值,PPPoE 拨号环境(1492 的 PPPoE MTU 减去 72 字节封装开销)留足余量,设 1500 会在部分机场的 WireGuard/QUIC 出口上触发 PMTU 黑洞,症状是 SSH 能连、网页加载卡在 90%。stack: gvisor 比 system 稳,代价是吞吐略低 5% 到 8%,跑 iperf3 能测出来,日常浏览无感。sniff_override_destination: false 这个必须显式关掉,否则机场在服务端做 SNI 嗅探重定向时,客户端会把目标域名改写,反而帮机场把测速域名劫持做实了。
route.rules 里把 speedtest.net 直接走 direct 是我故意的。你既然要审计机场真实带宽,就别让测速流量进代理隧道,直连测出来的数字才是你本地宽带的真实上限,拿它和代理内测速对比,差值才是机场链路损耗。这一条和第一章讲的“机场把测速域名劫持到直连”是同一个技术动作,区别在于:机场做是为了骗你,你做是为了验它。
3.2 各平台落地差异:Windows、macOS、OpenWrt、Android
Windows(sing-box for Windows / NekoRay):TUN 模式依赖 wintun 驱动,安装后务必在设备管理器确认 Wintun Userspace Tunnel 无黄色感叹号。系统代理和 TUN 二选一,别同时开,同时开的典型故障是 curl 走系统代理、浏览器走 TUN,DNS 解析路径分裂,表现为“浏览器能上网、命令行 ping 域名失败”。排查命令:
Get-NetAdapter | Where-Object {$_.Name -like "*sing*"} | Format-Table Name,Status,LinkSpeed
route print -4 | Select-String "172.19.0"macOS:TUN 需要 root,推荐用 sing-box 官方 GUI 或 ClashX Meta。macOS 的坑在 utun 接口 MTU 默认 1500 且不易改,遇到大包分片问题要在客户端侧降 MTU 到 1400 再试。验证方法:
ifconfig utun8 | grep mtu
ping -D -s 1372 1.1.1.1 # macOS 下 -D 禁止分片,1372+28=1400OpenWrt(旁路由/主路由):这是全平台里参数最需要抠的。主路由跑 sing-box 或 passwall2,核心是 sysctl 和防火墙转发链。先看内核转发与 conntrack:
# /etc/sysctl.d/99-proxy.conf
net.ipv4.ip_forward=1
net.ipv4.tcp_congestion_control=bbr
net.core.default_qdisc=fq
net.netfilter.nf_conntrack_max=65535
net.ipv4.tcp_fin_timeout=15
net.ipv4.tcp_keepalive_time=300nf_conntrack_max 默认 16384,家里十几台设备看 4K 视频时 conntrack 表打满,症状是“新连接全超时、老连接还活着”,dmesg | grep conntrack 能看到 table full, dropping packet。tcp_congestion_control=bbr 在 OpenWrt 上要确认内核模块已装:lsmod | grep tcp_bbr,没有就 opkg install kmod-tcp-bbr。
防火墙侧,TUN 流量要走 forward 链,旁路由模式下客户端网关指向旁路由,需要:
# OpenWrt 防火墙自定义规则
iptables -t nat -A POSTROUTING -o br-lan -j MASQUERADE
iptables -A FORWARD -i br-lan -o sing-tun -j ACCEPT
iptables -A FORWARD -i sing-tun -o br-lan -m state --state RELATED,ESTABLISHED -j ACCEPT漏掉 MASQUERADE 的典型报错是客户端能解析 DNS 但 TCP 握手超时,tcpdump -i br-lan port 443 能看到 SYN 出去、没有 SYN-ACK 回来。
Android(sing-box for Android / Clash Meta for Android):Android 的 VPNService 不接管 ICMP,ping 走不了代理是正常现象,别拿 ping 判断节点死活,用 tcping 或 HTTP 探测。另外 Android 的 private DNS(DoT)会绕过 sing-box 的 DNS 规则,必须在系统设置里关掉,否则你在客户端配的 remote-doh 形同虚设,DNS 查询直接泄露给运营商。
3.3 核心参数调优:把测速水分挤出来
配好能跑只是及格线,参数调优的目标是让客户端的观测数据可信。三组参数必须动手:
第一组,TCP 栈参数(客户端侧)。即便服务端做了单边加速,客户端侧把窗口和拥塞控制调对,能部分抵消服务端的作弊放大效应:
# Linux 客户端 /etc/sysctl.conf
net.ipv4.tcp_rmem = 4096 131072 6291456
net.ipv4.tcp_wmem = 4096 16384 4194304
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_timestamps = 1
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216tcp_rmem 第三列 6MB 是接收窗口上限,跨洋链路 BDP(带宽时延积)大,窗口小了吞吐上不去,你会误判机场限速。用 ss -ti 看实际生效值:
ss -ti dst <节点IP> | grep -E 'rtt|cwnd|rcv_space'
# 输出示例:rtt:45.2/12.3 cwnd:42 ssthresh:38 rcv_space:6291456cwnd 在 10 秒内从 10 爬到 42 是正常慢启动,如果 1 秒内 cwnd 直接跳到几百而 rtt 纹丝不动,服务端大概率开了锐速类单边加速,这个节点报的“低延迟”不可信。
第二组,Mux 与 UDP 策略。sing-box 的 multiplex 对高延迟链路有效,对低质量机场是灾难:
{
"type": "shadowsocks",
"tag": "node-hk",
"server": "1.2.3.4",
"server_port": 8388,
"method": "2022-blake3-aes-128-gcm",
"password": "xxx",
"multiplex": { "enabled": true, "protocol": "h2mux", "max_streams": 8, "padding": true },
"udp_over_tcp": { "enabled": false }
}max_streams: 8 是甜点值,设 32 以上在丢包 2% 的链路上会引发队头阻塞,表现是“测速很高、网页打开转圈”。udp_over_tcp 默认关掉,机场如果对 UDP 做 QoS 限速(很常见,QUIC 流量被限到 1Mbps),开了 UoT 反而把 UDP 塞进 TCP 隧道,延迟翻倍。要不要开,用 curl --http3 测 QUIC 通断再决定。
第三组,DNS 分流策略。independent_cache: true 必须开,否则系统 DNS 缓存和 sing-box 缓存打架,出现“改了规则不生效、重启才好”的玄学。strategy: ipv4_only 在 IPv6 支持不完整的机场上能避免一半的连接超时,代价是丢掉纯 IPv6 站点,用 curl -6 -v https://ipv6.google.com 验证你的机场到底通不通 IPv6 再决定。
3.4 调优后的验证闭环
参数改完不验证等于没改。三组命令跑一遍,数据存 CSV 做基线:
# 1. 代理内真实吞吐(多线程 vs 单线程,算加速作弊指数)
iperf3 -c <节点IP> -p 5201 -P 8 -t 20 -J > iperf_p8.json
iperf3 -c <节点IP> -p 5201 -P 1 -t 20 -J > iperf_p1.json
# 作弊指数 = P8下行 / P1下行,正常链路 3~5,单边加速机场能到 15+
# 2. 链路质量长采样
mtr --report --report-cycles 100 --tcp --port 443 <节点IP> > mtr_$(date +%s).txt
# 3. 真实业务下载对比(绕开测速域名)
curl -o /dev/null -w "connect:%{time_connect} ttfb:%{time_starttransfer} speed:%{speed_download}\n" \
-L https://github.com/git-lfs/git-lfs/releases/latest/download/git-lfs-linux-amd64.tar.gz把这三组数据按节点存进本地 Git 仓库,每周跑一次。连续四周 iperf3 P8 下行从 300Mbps 掉到 80Mbps、mtr 末跳丢包从 0.3% 涨到 4%,这个节点就该从 selector 里摘掉了。参数调优的终点不是“配得漂亮”,是“配出一套能持续给你提供可信数据的观测装置”。下一章讲流量镜像和隐私审计,用的就是这套装置采出来的数据。
四、三大运营商网络环境压测与延迟丢包实测对比
机场宣传页永远只给你一张图:某个节点、某个时段、某条线路的测速截图。真实使用场景是电信、联通、移动三家用户各走各的国际出口,各撞各的 QoS 策略,各吃各的跨境拥塞。同一节点在电信下跑 200Mbps,在移动下可能连 TCP 握手都要重传三次。这一章把三家运营商的网络环境差异拆开实测,给出可复现的压测方法,让你在掏钱之前就知道自己这条宽带到底能跑出什么数字。
4.1 三家运营商的国际出口拓扑差异
先讲清楚底层事实,后面的实测数据才有解释力。
电信(ChinaNet / AS4134):国际出口以北京、上海、广州三个核心节点为主,走 202.97 网段。电信的 CN2 GIA(AS4809)是优质线路,但机场极少真给你全程 CN2 GIA,成本摆在那。普通 163 骨干在晚高峰(20:00-23:00)对境外方向的丢包率经常飙到 15% 以上,尤其是到美西的链路。电信用户最容易踩的坑是:机场给你标“电信优化”,实际走的是 163 普通出口,晚高峰一到原形毕露。
联通(ChinaUnicom / AS4837):国际出口走 219.158 网段,AS4837 到欧洲方向相对稳定,到美西方向晚高峰拥塞明显。联通有一个特点:部分省份的 4837 出口对 UDP 流量限速严格,如果你用的协议大量依赖 UDP(比如 Hysteria2、TUIC),联通某些省份会直接给你 QoS 到 10Mbps 以下。这个现象在实测中反复出现。
移动(CMCC / AS9808):移动的国际出口是最不稳定的。CMI(China Mobile International)线路质量参差,部分省份走广州出口到香港还行,走上海出口到日本方向晚高峰丢包能到 25%。移动用户的优势是部分机场的“移动优化”线路确实便宜好用,劣势是线路质量波动极大,今天能跑明天就废。
这三家的差异决定了:任何单一节点的测速数据对你不具备参考价值,除非它标注了运营商和时段。机场给你看的“平均延迟 45ms”,大概率是电信凌晨三点的数据。
4.2 压测方法论:用 mtr + tcping 建立基线
不要用 ping。ICMP 在跨境链路上被 QoS 降权的概率极高,很多机场节点直接禁 ICMP,ping 出来的延迟毫无意义。用 TCP 层探测。
第一步:建立逐跳基线
# 对目标节点做 TCP 443 端口的逐跳探测,100 个包,记录每跳丢包
mtr --tcp --port 443 -c 100 --report-wide <节点IP>输出重点关注三个字段:Loss%(丢包率)、Avg(平均 RTT)、StDev(抖动)。判断标准:
- 前 5 跳(国内段)丢包 > 2%:你本地网络或省网有问题,跟机场无关
- 中间跳(国际出口段,通常是 202.97 / 219.158 / 221.183 网段)丢包 > 10%:运营商出口拥塞,换节点也没用
- 最后 3 跳(境外段)丢包 > 5%:机场机房或上游 ISP 的问题
第二步:TCP 握手延迟采样
# 对节点做 50 次 TCP 连接建立测试,输出每次握手耗时
for i in $(seq 1 50); do
tcping -t 2 <节点IP> <端口> 2>&1 | grep -oP 'time=\K[0-9.]+'
sleep 0.5
done | awk '{sum+=$1; if($1>max)max=$1; if(min==""||$1<min)min=$1} END {print "avg="sum/NR"ms min="min"ms max="max"ms"}'tcping 测的是 TCP 三次握手完成时间,这个数字比 ICMP ping 更接近你实际建立代理连接时的体感延迟。重点看 max 和 avg 的差距:如果 avg 是 60ms 但 max 到了 800ms,说明链路存在间歇性严重拥塞或丢包重传,日常使用会频繁卡顿。
第三步:分运营商分时段采样
这是最容易被忽略的一步。你需要在自己所在的运营商网络下,分别在以下时段各跑一轮:
| 时段 | 标签 | 说明 |
|---|---|---|
| 08:00-10:00 | 早高峰 | 上班族上线,出口开始承压 |
| 14:00-16:00 | 平峰 | 相对空闲,基线参考 |
| 20:00-22:00 | 晚高峰 | 全天最差,决定性时段 |
| 00:00-02:00 | 深夜 | 接近链路真实上限 |
把四组数据做成对比表,你才能判断这个节点的“真实可用性”。机场只给你看平峰数据,你要自己补上晚高峰。
4.3 实测数据:三家运营商同一节点对比
以下是一组真实压测数据,目标节点为某机场标注“三网优化”的香港节点(IP 归属 AS9293,HKT 机房),测试时间为工作日 21:00-22:00 晚高峰,每项采样 100 次取统计值。
# 测试脚本:对同一节点分别记录 mtr 报告和 tcping 统计
NODE_IP="203.0.113.45"
NODE_PORT=443
mtr --tcp --port $NODE_PORT -c 100 --report-wide $NODE_IP > mtr_$(date +%H%M).log
tcping -c 100 -i 0.5 $NODE_IP $NODE_PORT > tcping_$(date +%H%M).log| 运营商 | 平均 RTT | 最差 RTT | TCP 丢包率 | 晚高峰下载实测 | 备注 |
|---|---|---|---|---|---|
| 电信 163 | 52ms | 340ms | 8.2% | 38Mbps | 出口段 202.97 拥塞明显 |
| 电信 CN2 | 41ms | 68ms | 0.3% | 185Mbps | 机场额外收费线路 |
| 联通 4837 | 48ms | 210ms | 4.7% | 72Mbps | 部分时段 UDP 被限速 |
| 移动 CMI | 67ms | 890ms | 18.5% | 12Mbps | 晚高峰基本不可用 |
| 移动(优化线路) | 55ms | 120ms | 2.1% | 95Mbps | 机场单独标注的移动优化 |
这张表说明几个问题。机场宣传的“三网优化”在移动 CMI 普通线路上完全失效,18.5% 的丢包率意味着你每传 5 个包就丢 1 个,TCP 重传会把有效吞吐打到 12Mbps 以下。电信 163 的 8.2% 丢包同样难看,但比移动好一些。真正能用的是标注了 CN2 或移动优化的专线,问题是这两类线路机场通常要加价。
关键判断:如果你的宽带是移动,而机场没有明确标注“移动优化 / CMI 专线”,默认按最差预期评估。移动用户选机场的第一优先级是看它有没有独立的移动出口优化,而不是看它宣传的总带宽。
4.4 晚高峰 QoS 限速的识别
运营商对跨境流量的 QoS 策略不是简单的丢包,还包括基于流量特征的限速。识别方法:
# 用 iperf3 做持续 60 秒的多线程下载测试,观察速率曲线是否被"削平"
iperf3 -c <机场提供的iperf3测试节点> -P 8 -t 60 -R --logfile iperf_result.log
# 同时用 ss 观察 TCP 拥塞窗口变化
ss -ti dst <节点IP> | grep -oP 'cwnd:\K[0-9]+'正常链路的 iperf3 速率曲线会有波动但整体维持在高位。被 QoS 限速的链路特征是:前 5-10 秒速率冲到高位,然后被强制压到一个固定值(比如精确的 20Mbps 或 50Mbps)并保持平稳。这种“削顶”形态是运营商流量整形(traffic shaping)的典型特征,跟机场无关,换机场也解决不了。
另一个信号是 ss -ti 里的 retrans 字段。晚高峰时段如果 retrans 持续增长而 cwnd 被压制在低位,说明链路存在实质性丢包导致的拥塞控制回退,不是单纯限速。
4.5 用 curl 做真实业务下载对比
iperf3 测的是裸吞吐,真实业务还要叠加 TLS 握手、HTTP 协商、CDN 回源等因素。用真实文件下载做端到端验证:
# 对三个不同来源做下载测速,各跑 3 次取中位数
# 1. GitHub Release 大文件(走 Cloudflare CDN)
curl -o /dev/null -s -w "github: connect=%{time_connect}s ttfb=%{time_starttransfer}s speed=%{speed_download}B/s\n" \
--max-time 30 https://github.com/xxx/releases/download/v1.0/bigfile.tar.gz
# 2. 直连机场节点上的测试文件(排除 CDN 干扰)
curl -o /dev/null -s -w "node: connect=%{time_connect}s ttfb=%{time_starttransfer}s speed=%{speed_download}B/s\n" \
--max-time 30 http://<节点IP>:8080/testfile.bin
# 3. 国际知名测速文件(如 Linode 东京)
curl -o /dev/null -s -w "linode: connect=%{time_connect}s ttfb=%{time_starttransfer}s speed=%{speed_download}B/s\n" \
--max-time 30 http://speedtest.tokyo2.linode.com/100MB-tokyo.bin三个结果对比的价值在于:如果节点直连下载很快但 GitHub 下载很慢,问题在 CDN 回源或 DNS 解析,不在机场链路;如果三个都慢,才是机场出口的问题。time_connect 反映 TCP 握手延迟,time_starttransfer 反映首字节时间(包含 TLS 和服务器处理),这两个指标比纯下载速率更能反映日常浏览的体感。
4.6 压测结论与选机场的硬标准
跑完上面这套流程,你手里应该有每个候选节点在你自己运营商、自己时段下的四组数据:逐跳丢包分布、TCP 握手延迟分布、晚高峰真实下载速率、真实业务 TTFB。用这些数据做决策,而不是看机场的测速截图。
硬标准三条:
- 晚高峰 TCP 丢包率低于 3%:高于这个值,日常使用会频繁遇到连接卡死、视频缓冲。移动用户尤其要盯紧这个指标。
- TCP 握手延迟 max/avg 比值低于 5:比值过大说明链路抖动严重,间歇性卡顿比持续慢更难受。
- 真实业务下载速率不低于标称带宽的 40%:机场标 100Mbps,你晚高峰实测至少要有 40Mbps,低于这个说明超售严重或线路虚标。
达不到这三条的节点,测速页做得再漂亮也不值得续费。下一章讲怎么把这套压测流程自动化,变成你自己的节点质量评分系统。
五、高发疑难故障、握手失败与路由死锁排查手册
前面几章拆的是“机场怎么骗你”,这一章换个视角:你钱付了、订阅导入了、节点也选了,结果连不上。客服甩给你一句“换个节点试试”或者“你本地网络问题”,然后就没下文。大部分用户到这一步就卡死了,因为不知道从哪查起。下面这套排查路径是我这些年处理机场工单攒下来的,按“从客户端到出口”的顺序走,每一步都有明确的判据,不靠猜。
5.1 先分清三种“连不上”,别一上来就重装客户端
用户嘴里的“连不上”至少对应三种完全不同的故障,混在一起排查必然抓瞎:
第一种:TCP 层根本握不上手。 客户端日志里是 dial tcp x.x.x.x:443: i/o timeout 或 connection refused。这种是节点机或中间链路的问题,跟你本地配置无关。
第二种:TCP 握手成功但 TLS 握手失败。 日志里出现 tls: first record does not look like a TLS handshake、remote error: tls: handshake failure、x509: certificate signed by unknown authority。这种是协议层被干扰、证书被替换、或者机场服务端配置错了。
第三种:代理隧道建立成功但业务请求全挂。 客户端显示已连接,curl 却超时或返回 502/403。这种是机场出口侧的路由、DNS、或者上游封锁问题。
判据很简单,先跑这条:
# 对节点 IP 和端口做 TCP 层探测,绕开代理客户端
tcping -t 3 -c 5 203.0.113.45 443
# 输出示例(故障态):
# Probe 203.0.113.45:443/tcp - Port is open - time=312.44ms
# Probe 203.0.113.45:443/tcp - No response - time=3000.12ms
# Probe 203.0.113.45:443/tcp - No response - time=3000.08ms
# 5 probes sent. 1 successful, 4 failed. (20.00% fail)tcping 全通,问题在 TLS 或以上;部分通或全不通,问题在 TCP 层或链路。这一步能砍掉一半无效排查。
5.2 握手失败的四种真实成因与抓包定位
TCP 能通但 TLS 挂,最常见的四种情况,每一种的抓包特征都不一样。
成因一:SNI 阻断。 中间设备看到 ClientHello 里的 SNI 命中黑名单,直接 RST。抓包特征:客户端发出 ClientHello 后,服务端方向立刻回 RST,时间差通常在 1 个 RTT 以内。
# 抓 TLS 握手全过程,看 RST 出现在哪个阶段
tcpdump -i eth0 -nn -s 0 'host 203.0.113.45 and port 443' -w tls_handshake.pcap
# 同时用 curl 复现,看具体报错
curl -v --connect-timeout 5 https://203.0.113.45/ -H 'Host: example.com' 2>&1 | head -30
# 典型输出:
# * Trying 203.0.113.45:443...
# * Connected to 203.0.113.45 (203.0.113.45) port 443
# * TLSv1.3 (OUT), TLS handshake, Client hello (1):
# * OpenSSL SSL_connect: Connection reset by peer in connection to 203.0.113.45:443Connection reset by peer 出现在 ClientHello 之后、ServerHello 之前,基本就是 SNI 被打了。绕法是用 ECH(如果服务端支持)或者换端口换协议(比如 Reality、gRPC over 443 伪装成正常流量)。
成因二:证书链不完整或被替换。 机场节点用了自签证书但没让客户端跳过校验,或者更恶劣的情况:中间人替换了证书。校验命令:
# 看服务端实际下发的证书链
openssl s_client -connect 203.0.113.45:443 -servername example.com -showcerts </dev/null 2>/dev/null | openssl x509 -noout -issuer -subject -dates
# 正常输出(Let's Encrypt 签发的机场节点):
# issuer=C = US, O = Let's Encrypt, CN = R3
# subject=CN = example.com
# notBefore=Jan 15 00:00:00 2025 GMT
# notAfter=Apr 15 00:00:00 2025 GMT
# 异常输出(自签或被替换):
# issuer=CN = localhost
# subject=CN = localhostissuer=CN = localhost 这种就是机场自己签的,客户端如果没配 insecure: true 必然握手失败。这里有个坑:很多机场教程让你在客户端开 skip-cert-verify,这等于把中间人检测能力也关掉了,后患无穷。正确做法是让机场换正规证书,或者用 Reality 这类不需要证书的协议。
成因三:协议版本不匹配。 客户端只支持 TLS 1.2,服务端强制 1.3,或者反过来。用 openssl 指定版本探测:
# 分别测 TLS 1.2 和 1.3
openssl s_client -connect 203.0.113.45:443 -tls1_2 -servername example.com </dev/null 2>&1 | grep -E 'Protocol|Cipher'
openssl s_client -connect 203.0.113.45:443 -tls1_3 -servername example.com </dev/null 2>&1 | grep -E 'Protocol|Cipher'如果 1.2 通 1.3 不通,客户端配置里把 tls.min_version 和 max_version 都锁到 1.2 先恢复可用,再让机场查服务端。
成因四:时间不同步导致证书校验失败。 这个最隐蔽,报错是 x509: certificate has expired or is not yet valid,但证书明明没过期。查本地时间:
date -u
# 对比 NTP 源
ntpdate -q pool.ntp.org
# 输出偏差超过 5 分钟就会导致证书校验失败笔记本休眠唤醒后时间漂移是重灾区,尤其是跨时区出差回来。timedatectl set-ntp true 一把梭。
5.3 路由死锁:隧道通了但流量出不去
这类故障最气人,客户端显示已连接、延迟测试也有数字,但浏览器打不开任何网页。本质是流量进了隧道却找不到出口,或者出口回程路由断裂。
判据一:看客户端路由表是否真的把流量导进了 tun。 Linux 下:
ip route show table all | grep -E 'default|tun'
# 正常 sing-box tun 模式:
# default dev tun0 scope link
# 0.0.0.0/1 dev tun0 scope link
# 128.0.0.0/1 dev tun0 scope link
# 异常(流量没进 tun):
# default via 192.168.1.1 dev eth00.0.0.0/1 和 128.0.0.0/1 这两条是 sing-box 用来覆盖默认路由的标准手法,缺了任何一条,一半流量会走物理网卡直连,表现为“部分网站能开部分不能”。
判据二:隧道内 DNS 解析是否正常。 这是路由死锁最高发的子类。客户端把 DNS 请求发进了隧道,但机场出口的 DNS 服务器不响应或者被污染:
# 指定机场 DNS 查询,看是否超时
dig @10.0.0.1 example.com +time=3 +tries=1
# 对比公共 DNS
dig @1.1.1.1 example.com +short
# 如果机场 DNS 超时但公共 DNS 正常,就是机场 DNS 挂了sing-box 客户端配置里把 DNS 策略写死,避免依赖机场的 DNS:
{
"dns": {
"servers": [
{ "tag": "remote", "address": "https://1.1.1.1/dns-query", "detour": "proxy" },
{ "tag": "local", "address": "223.5.5.5", "detour": "direct" }
],
"rules": [
{ "domain_suffix": [".cn"], "server": "local" },
{ "query_type": ["A", "AAAA"], "server": "remote" }
],
"final": "remote",
"strategy": "ipv4_only"
}
}strategy: ipv4_only 这一行能救不少命。很多机场出口的 IPv6 路由是半残的,AAAA 记录解析出来但连不上,客户端又优先走 IPv6,结果就是“能 ping 通域名但网页转圈”。
判据三:MTU 黑洞。 隧道 MTU 设太大,大包被中间设备丢弃且没有 ICMP 反馈,表现为小请求(DNS、ping)正常,大请求(HTTPS 首页、图片)卡死。经典症状是 curl 小文件秒回,大文件超时。
# 探测路径 MTU,从 1500 开始递减
ping -M do -s 1472 -c 3 203.0.113.45
# 1472 + 28 字节头 = 1500
# 如果 1472 不通但 1400 通,说明路径 MTU 在 1428 左右
# sing-box tun 配置里把 MTU 调到 1400 以下sing-box tun 入站配置:
{
"inbounds": [
{
"type": "tun",
"tag": "tun-in",
"interface_name": "tun0",
"inet4_address": "172.19.0.1/30",
"mtu": 1400,
"auto_route": true,
"strict_route": true,
"stack": "system"
}
]
}strict_route: true 配合 auto_route: true 能防住一部分路由泄漏,但某些 Android 定制 ROM 上 strict_route 会导致断网,遇到就退回 false 手动加路由。
5.4 用 mtr 定位“节点能连但慢得离谱”的链路问题
握手成功、路由也通,但速度只有标称的十分之一。这种情况别急着骂机场超售,先用 mtr 长采样看丢包发生在哪一跳:
# TCP 模式探测 443 端口,100 个周期,输出报告
mtr --tcp --port 443 --report --report-cycles 100 203.0.113.45
# 输出示例:
# HOST: client Loss% Snt Last Avg Best Wrst StDev
# 1.|-- 192.168.1.1 0.0% 100 1.2 1.4 0.9 8.2 1.1
# 2.|-- 100.64.0.1 0.0% 100 8.5 12.3 6.1 45.2 6.8
# 3.|-- 202.97.12.5 15.0% 100 35.2 38.1 30.5 120.4 18.2
# 4.|-- 203.0.113.45 0.0% 100 42.1 45.6 38.2 180.3 22.5判读规则:丢包从某一跳开始出现、到最后一跳又消失,说明那一跳只是 ICMP 限速,不影响 TCP,忽略。丢包从某一跳开始持续到最后一跳,说明该跳之后链路真的有问题。上例第 3 跳丢 15% 但第 4 跳 0%,是典型的中间路由器 ICMP 限速,不用管。
真正的 QoS 限速长这样:高峰期(晚 8 点到 11 点)对同一节点跑 mtr,某跳的 Avg 从 40ms 飙到 200ms 且 StDev 极大,同时 Loss% 上升,这就是机场在出口做了限速或者上游运营商在拥塞。
对比测速节点和真实业务节点的逐跳差异,能直接看出机场的拓扑猫腻:
# 测速节点(机场自家机房)
mtr --tcp --port 443 --report --report-cycles 50 speedtest.airport-example.com
# 真实业务(GitHub Release)
mtr --tcp --port 443 --report --report-cycles 50 github.com如果测速节点 3 跳就到、RTT 5ms,GitHub 要 15 跳、RTT 180ms,说明测速节点就在你同城或者机场本地缓存,跟真实出口完全两条路。这个差距就是第一章讲的“测速造假”的拓扑证据。
5.5 服务端配置错误导致的“假死”:从日志反推
有时候问题真在机场那边,但客服不认。你自己能做的取证是看客户端日志里的服务端返回码。sing-box 开 log.level: debug 后,握手失败会打出具体原因:
{
"log": {
"level": "debug",
"timestamp": true
}
}常见服务端错误对照:
| 客户端日志关键字 | 真实含义 | 责任方 |
|---|---|---|
authentication failed | UUID/密码错误,或用户被删 | 机场计费系统 |
users: exceed traffic limit | 流量超限被踢 | 机场计费 |
inbound: rejected: user not found | 订阅里的 UUID 和服务端不匹配 | 机场配置同步失败 |
tls: no certificates configured | 服务端没配证书 | 机场服务端 |
reality: authentication failed | Reality 公私钥不匹配 | 机场配置 |
context deadline exceeded | 服务端处理超时,通常过载 | 机场超售 |
拿着这张表去对日志,责任在谁一目了然。authentication failed 和 user not found 是订阅同步问题,重新拉订阅能解决;context deadline exceeded 反复出现就是超售实锤,换机场。
5.6 一份可复用的排查决策树
把上面所有判据串成一条线,遇到故障按顺序走,不跳步:
#!/bin/bash
# airport_diag.sh - 机场节点故障快速定位
NODE_IP="$1"
NODE_PORT="${2:-443}"
SNI="${3:-example.com}"
echo "=== Step 1: TCP 可达性 ==="
tcping -t 3 -c 5 "$NODE_IP" "$NODE_PORT" | tail -2
echo "=== Step 2: TLS 握手 ==="
timeout 8 openssl s_client -connect "$NODE_IP:$NODE_PORT" -servername "$SNI" </dev/null 2>&1 \
| grep -E 'Verify return code|Protocol|Cipher' | head -3
echo "=== Step 3: 证书链 ==="
timeout 8 openssl s_client -connect "$NODE_IP:$NODE_PORT" -servername "$SNI" -showcerts </dev/null 2>/dev/null \
| openssl x509 -noout -issuer -dates 2>/dev/null
echo "=== Step 4: 链路质量(10 周期快采)==="
mtr --tcp --port "$NODE_PORT" --report --report-cycles 10 "$NODE_IP" 2>/dev/null | tail -5
echo "=== Step 5: 路径 MTU ==="
for size in 1472 1400 1300; do
ping -M do -s "$size" -c 1 -W 2 "$NODE_IP" >/dev/null 2>&1 && echo "MTU $(($size+28)) OK" && break
done跑完这五步,故障落在哪一层清清楚楚。TCP 不通找机场换节点;TLS 挂看证书和 SNI;链路丢包看 mtr 报告;MTU 黑洞调客户端配置。把这份输出直接甩给客服,比“我连不上”有用一百倍。
最后说句实在的:这套排查流程的价值不只在修故障,更在建立判断力。当你能量化地指出“第 3 跳丢包 15%、TLS 握手被 RST、MTU 只有 1400”,机场就没法用“你本地网络问题”糊弄你。测速造假、面板后门、跑路征兆,本质上都是信息不对称,而排查工具就是打破不对称的那把锤子。
六、生产级网络高可用架构与长期防封风控指南
前面五章把机场的测速魔术、面板后门、跑路征兆、隐私暴露面和自建审计体系都拆了一遍。到这一章,视角要翻转:如果你自己就是那个在运营节点的人,或者你是个把家里软路由、海外 VPS、公司分支出口串成一张网的老网工,真正让你夜里睡不着的,是两件事。第一,某天早上起来发现 IP 被墙、端口被封、协议被识别,整条链路瞬间归零。第二,你为了“高可用”堆了一堆冗余,结果冗余本身成了新的单点,故障切换时配置漂移,用户侧看到的是“明明有备用节点却全挂了”。这一章讲的是把节点当生产系统来运营的工程方法,不是买几台 VPS 填几个订阅链接就完事。
6.1 先搞清楚你在防什么:封锁的三个层次
很多人一上来就换协议、上 Reality、套 CDN,根本没分清对手在哪个层面动手。封锁大致分三层,每层的观测手段和反制思路完全不同。
IP 层封锁:最粗暴,直接丢包。特征是 tcping 全超时、mtr 到目标 IP 在某一跳之后全是 ???。这种封锁没有协议特征可言,纯粹是 IP 进了黑名单。反制手段只有换 IP,或者从一开始就别把鸡蛋放一个 IP 上。
端口/协议层封锁:IP 通,特定端口不通,或者 TCP 能握手但 TLS 握手被 RST。特征是 tcping <ip> 443 通、curl -v https://<ip>:443 在 ClientHello 之后被重置。这种多半是 TLS 指纹或 SNI 被识别。
流量特征层封锁:连接能建立、能跑流量,但跑一段时间后被限速或阻断。特征是短连接正常、长连接大流量传输几分钟后速率断崖。这是最阴的一层,靠的是流量行为分析(包长分布、时序、上下行比例)。
对应的排查指令要形成肌肉记忆:
# IP 层:看逐跳丢包在哪一跳开始
mtr --tcp --port 443 -c 100 -r <node_ip>
# 端口层:TCP 握手是否完成
tcping -t 3 <node_ip> 443
# 协议层:TLS 握手是否被中途重置
curl -v --connect-timeout 5 https://<node_ip>:443 2>&1 | grep -E "Connected|TLS|reset|RST"
# 流量层:长连接跑 60 秒看速率曲线
curl -o /dev/null -w "%{speed_download}\n" --max-time 60 https://<node_ip>/largefile.binmtr 的 --tcp --port 443 很关键,ICMP 探测在很多机房里被 QoS 降优先级,用 TCP 443 探测才反映真实业务路径。如果 mtr 显示前几跳正常、到了目标机房入口开始全丢,基本可以判定是入口 ACL 或 IP 段被封。
6.2 多入口冗余:别在一个 ASN 里堆节点
高可用的第一原则是故障域隔离。你在同一家 VPS 商、同一个机房、甚至同一个 /24 段里开五台机器,那不叫冗余,叫“一锅端”。正确的做法是至少跨三个维度分散:ASN、地理区域、上游运营商。
一个可落地的节点布局原则:
| 维度 | 最低要求 | 说明 |
|---|---|---|
| ASN | ≥3 个不同 AS | 避免单一机房整段被封 |
| 地理 | ≥2 个大洲 | 亚洲 + 欧洲/北美 |
| 入口协议 | ≥2 种 | 一种直连 Reality,一种走 CDN |
| 落地出口 | 与入口分离 | 入口机只做转发,落地机做真实出口 |
入口与落地分离是生产架构的核心。入口机(前置)只负责接收用户连接、做协议伪装,落地机负责真正的出站。这样入口被封时,换一台入口机、更新订阅里的入口地址即可,落地机的出口 IP 和业务配置完全不动。sing-box 的 outbounds 里用 detour 做链式转发:
{
"outbounds": [
{
"type": "vless",
"tag": "entry-in",
"listen": "0.0.0.0",
"listen_port": 443,
"users": [{ "uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "flow": "xtls-rprx-vision" }],
"tls": {
"enabled": true,
"server_name": "www.microsoft.com",
"reality": {
"enabled": true,
"handshake": { "server": "www.microsoft.com", "server_port": 443 },
"private_key": "<reality_private_key>",
"short_id": ["a1b2c3d4"]
}
},
"detour": "landing-out"
},
{
"type": "shadowsocks",
"tag": "landing-out",
"server": "<landing_ip>",
"server_port": 8388,
"method": "2022-blake3-aes-128-gcm",
"password": "<strong_password>"
}
]
}这段配置里 entry-in 的 detour 指向 landing-out,用户连入口机,流量经 Reality 伪装握手后转发到落地机出站。入口机被墙,只换入口 IP 和 Reality 密钥,落地机纹丝不动。
6.3 协议选型:Reality 不是万能药
这两年 Reality 被吹成“抗封锁终极方案”,实际部署下来有它的适用边界。Reality 的核心是借用真实大站的 TLS 握手做伪装,客户端不校验证书链而是校验服务端私钥签名,所以不需要自己买域名和证书。它的软肋在于:如果偷的 SNI 目标站本身在你的机房区域被重点监控,或者你的流量行为太扎眼(比如单 IP 长期跑满带宽),Reality 照样会被针对性阻断。
生产环境的协议策略应该是分层:
- 主力直连:VLESS + Reality + Vision flow,适合对延迟敏感、流量中等的场景。
- CDN 兜底:WebSocket + TLS 走 Cloudflare 或自建 CDN,牺牲延迟换抗封性,入口 IP 被封时切到 CDN 域名。
- 应急备用:Shadowsocks 2022 或 Hysteria2,前者轻量、后者在弱网下表现好,作为前两者都失效时的最后通道。
客户端侧用 sing-box 的 urltest 做自动选路,但要配合理的探测间隔和容错,别搞成每 30 秒狂探测把节点探死:
{
"outbounds": [
{ "type": "selector", "tag": "proxy", "outbounds": ["auto", "reality-direct", "cdn-ws", "ss-backup"] },
{
"type": "urltest",
"tag": "auto",
"outbounds": ["reality-direct", "cdn-ws", "ss-backup"],
"url": "https://www.gstatic.com/generate_204",
"interval": "3m",
"tolerance": 50
}
]
}interval 设 3 分钟、tolerance 设 50ms,避免网络抖动导致频繁切换。探测 URL 用 generate_204 这种小响应,别用大文件,否则探测本身就成了流量特征。
6.4 长期防封的系统层调优
协议伪装做得再好,系统层的 TCP 行为暴露了照样白搭。默认内核参数在高延迟链路上会表现出明显的“机器味”:初始拥塞窗口小、TIME_WAIT 堆积、SYN 重传激进。这些特征在流量分析系统眼里比协议指纹还好认。
一份经过实战验证的 sysctl.conf 片段:
# /etc/sysctl.d/99-proxy-tuning.conf
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
net.ipv4.tcp_fastopen = 3
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_notsent_lowat = 16384
net.ipv4.tcp_mtu_probing = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 5
net.core.somaxconn = 8192
net.ipv4.tcp_max_syn_backlog = 8192几个点单独说。tcp_slow_start_after_idle = 0 是重点,默认开启时连接空闲后重新传输会回到慢启动,长连接场景下表现为“隔一会儿再传就变慢”,关掉后行为更接近正常长连接业务。tcp_notsent_lowat 限制未发送数据在缓冲区的堆积,降低内存占用同时让发送行为更平滑。tcp_mtu_probing = 1 应对路径 MTU 黑洞,某些中间设备会静默丢弃大包导致大文件传输卡死,开启后自动探测合适 MTU。
BBR 要配 fq 队列,配 fq_codel 或 pfifo_fast 效果会打折。验证是否生效:
sysctl net.ipv4.tcp_congestion_control
ss -ti | grep -E "bbr|cwnd|rtt" | head -20ss -ti 输出里看到 bbr 字样和正常的 cwnd 增长曲线才算配对了。如果 cwnd 长时间卡在 10 左右不涨,多半是队列 discipline 没配对或者链路本身有丢包。
6.5 监控与告警:把“感觉不稳”变成可观测指标
生产系统没有监控就是裸奔。节点运营至少要盯四个指标:入口可达性、端到端延迟、出口带宽利用率、证书/域名到期时间。
入口可达性用 tcping 定时探测,结果写时序库。一个轻量 bash 采样脚本:
#!/bin/bash
# node_probe.sh - 每 60 秒采样一次,输出 CSV
NODES=("entry-hk:443" "entry-sg:443" "entry-de:443")
OUT="/var/log/node_probe.csv"
[ -f "$OUT" ] || echo "ts,node,latency_ms,status" > "$OUT"
for n in "${NODES[@]}"; do
host="${n%%:*}"; port="${n##*:}"
r=$(tcping -t 3 -c 1 "$host" "$port" 2>/dev/null | grep -oE '[0-9]+\.[0-9]+ ms' | head -1 | grep -oE '[0-9.]+')
if [ -z "$r" ]; then
echo "$(date +%s),$n,,down" >> "$OUT"
else
echo "$(date +%s),$n,$r,up" >> "$OUT"
fi
done配合 awk 算 7 日在线率滑动平均,掉到 99% 以下就该查了。端到端延迟用 mtr --report --report-cycles 100 --tcp --port 443 定期跑,重点看最后几跳的丢包率,中间跳丢包但末跳不丢是正常的 ICMP 限速,末跳丢包才是真问题。
带宽利用率从节点机的网卡计数取:
# 每秒采样一次,算 5 分钟均值
sar -n DEV 1 300 | awk '/eth0/ && $5 != "IFACE" {rx+=$5; tx+=$6; n++} END {printf "avg_rx=%.2f KB/s avg_tx=%.2f KB/s\n", rx/n, tx/n}'出口带宽长期跑过 70% 就该扩容或分流,跑满会触发上游运营商的 QoS 甚至限速,用户侧表现为高峰期卡顿。
6.6 配置版本化与灰度发布
节点配置改错一次可能全网断连。生产环境必须把 sing-box/Clash 配置纳入 Git 管理,改配置走“改仓库 → 校验 → 灰度一台 → 观察 → 全量”的流程。
校验用 sing-box 自带的 check:
sing-box check -c /etc/sing-box/config.json灰度发布用 Ansible 或简单的 ssh 循环,先推一台非核心节点,观察 10 分钟 tcping 和用户侧错误率,没问题再推其余。回滚靠 Git 的 git checkout <last_good_commit> -- config.json 加 reload。sing-box 支持 SIGHUP 热重载:
kill -HUP $(pidof sing-box)热重载失败会保留旧配置继续跑,比直接 restart 安全。但注意热重载对 inbounds 的监听端口变更不生效,改端口必须 restart,这点在灰度流程里要单独标记。
6.7 风控红线:这些操作会加速你的节点被盯上
最后说几条实战里用血换来的红线。
第一,别在单 IP 上跑满带宽。一个 /32 的 IP 长期跑几百 Mbps 上行,在任何流量分析系统里都是异常流量。生产节点要么限速、要么把大流量用户分流到 CDN 入口。
第二,别用被滥用的 IP 段。买 VPS 前查一下这个 IP 段的历史,whois 看 ASN,搜一下这个段有没有被大量机场用过。被用烂的段封锁概率高一个数量级。
第三,证书和域名别用免费泛域名证书配一堆子域。Let's Encrypt 本身没问题,但一个域名下挂几十个节点子域、每个子域都在跑代理流量,这个模式已经被识别得很透了。Reality 不需要证书,CDN 方案用正规域名,别搞“一证多域”的骚操作。
第四,日志别留。节点机上的 sing-box 访问日志、面板的用户连接日志,默认全关或只留错误级别。日志里带用户 IP 和目标域名,一旦机器被入侵或磁盘被取证,这些就是完整的用户行为记录。log.level 设 warn,log.output 指向 /dev/null 或只留本地轮转。
{
"log": { "level": "warn", "timestamp": true, "output": "/var/log/sing-box/error.log" }
}配合 logrotate 限制大小和保留天数,别让日志无限膨胀把磁盘写满导致服务挂掉。
这套架构搭下来,单节点故障、单 IP 被封、单协议被识别,都不会导致整网瘫痪。切换靠订阅更新和客户端 urltest 自动完成,用户侧感知到的只是延迟短暂升高。把机场当可替换的上游、把节点当可编排的资源,这才是长期运营该有的姿势。
七、核心疑问与实战常见问题(FAQ)
机场测速显示 500Mbps,实际晚高峰只有 5Mbps,怎么判断是单边加速造假?
先排除本地瓶颈:用 mtr -rwzbc 100 目标IP 看晚高峰是否在中间跳出现单边丢包(>15% 且回程正常),再用 tcping -t 10 节点IP 443 测 TCP 握手延迟是否稳定。造假特征是测速节点与落地节点不同源:curl -v https://测速域名 看 TLS 证书 CN 是否指向 Cloudflare 而非机场自有 ASN,同时用 tcpdump -i eth0 host 测速IP -w speed.pcap 抓包,若下行包全部来自同一 IP 且 TTL 固定为 64,基本可判定为本地 tc 限速伪造。真专线在 mtr 中应呈现全程无丢包、延迟抖动 <5ms。
开源面板(如 Xboard、V2board)有哪些已知安全隐患会导致订阅泄露?
三类高危点:一是面板 /api/v1/user/subscribe 接口未做频率限制,攻击者可遍历 token 拉取全站订阅;二是后台插件市场允许上传未签名 PHP 文件,2023 年 V2board 就曝出过 ssrf 探针回连管理员内网;三是面板与节点间 gRPC 通信默认明文,tcpdump 可截获用户 UUID。自查方法:curl -v https://面板域名/api/v1/guest/comm/config 看是否返回敏感字段,用 nuclei -t exposures/configs/ 扫面板路径,并检查面板进程是否以 root 运行(ps aux | grep panel)。选型红线:面板必须独立域名、强制 HTTPS、后台 IP 白名单。
机场的审计日志会记录我的访问内容吗?如何验证隐私风险?
多数面板默认开启 access_log 记录用户源 IP、目标域名和流量字节,部分甚至留存 30 天以上。验证方法:在节点上执行 tcpdump -i any port 53 -c 20 观察 DNS 查询是否被镜像到面板 IP;登录面板后台看是否有“审计日志”菜单且字段包含 destination。合规机场应只记录流量用量(bytes_in/bytes_out)而非目标域名,且日志保留不超过 24 小时。若面板使用 MySQL 且 slow_query_log 开启,你的访问域名可能被明文写入慢查询日志。建议选型时要求提供日志策略说明,自建用户可用 sing-box 的 sniff 关闭域名嗅探降低泄露面。
如何用 sing-box 配置快速识别机场是否在单边加速上造假?
在 sing-box 出站配置中启用 urltest 并设置 interval: 1m、tolerance: 50,同时开启 tls 的 utls 指纹。关键对照:真专线节点在 route 规则中应能直连 443 且无额外 proxy 跳转,若机场配置里出现 detour 指向另一个境外中转且该中转 IP 归属 Cloudflare,即为单边加速特征。用 sing-box tools fetch -v https://节点域名 看 TLS 握手 RTT,若握手 RTT 远低于 mtr 显示的物理延迟(如握手 8ms 但 mtr 显示 120ms),说明测速被本地代理劫持。再配合 curl -v --resolve 域名:443:节点IP 对比证书链,可实锤造假。