需要国内有公网 IP ,跑了约一年的时间,非常的稳定,各种开大会都很稳定。
通过日志观察,ssh 连接不会被异常中断,最长一次 8 个 ssh 连接存活了 30 天,直到重新拨号。因为国内有公网 IP 的家宽不多,所以猜测这个方向的审查力度较弱。同时长连接也避免了 per connection 都要往远端创建一个 tcp 长连接的问题(之前试过 mihomo 自带的 mux ,体感对性能影响较大)。
从性能上来看,似乎是直接跳过了流量的明细审查(也有可能是 ssh 协议豁免,没仔细测试),表现在,如果正向建联( trojan-go ),speedtest 只能到 400Mbps ,通过 ssh 反向隧道,能打到 1400Mbps ,等同于走 cloudfront cdn 接入的性能。
下面是配方,仅供参考,没尝试非 ssh 的其他协议(比如 frp ),也可以自行尝试其他反向连接的协议。
整体架构
家庭路由器具有公网可访问地址,Mihomo 内置一个 SSH Server 。VPS 上的 ssh-reverse-agent 作为 SSH Client ,主动建立 8 条 SSH 长连接到路由器。
业务流量方向如下:
局域网设备
│ TCP
▼
家庭路由器上的 Mihomo
│ 规则匹配 ssh-reverse 出站
│ 从 8 条 SSH 长连接中轮询选择一条
│ SSH Server 主动打开业务 Channel
▼
VPS 上的 ssh-reverse-agent
│ 建立到目标的 TCP 连接
▼
目标服务器
注意:SSH 长连接由 VPS 主动连回家庭路由器,但业务 Channel 由 家庭路由器上的 SSH Server 主动向 VPS 的 SSH Client 打开。使用 Go 的 golang.org/x/crypto/ssh 实现,SSH Server 必须集成在 Mihomo 中,不依赖路由器上的 OpenSSH 或 Dropbear 。
Mihomo 侧实现
1. 新增顶层配置 ssh-reverse-servers ,用于配置监听地址、SSH 主机私钥和允许接入的 agent 公钥。
2. 新增出站类型 ssh-reverse ,通过 server-ref 引用本地 SSH Server ,通过 agent-id 选择对应 VPS 。
3. 维护已认证的 SSH 会话池,按 agent 和连接槽位管理;连接断开后移除,重连注册后替换旧会话。
4. 收到出站 TCP 请求时,使用原子计数器进行轮询,选择一条可用 SSH 会话。
5. 调用该会话的 OpenChannel ,使用自定义 Channel 类型,例如 [email protected] 。通过 Channel 的附加数据传递协议版本、目标主机名、端口和拨号超时。
6. 将打开成功的 Channel 包装成 Mihomo 出站接口需要的 net.Conn ,接入现有流量转发逻辑。
示例配置:
ssh-reverse-servers:
- name: home-entry
listen: 0.0.0.0:122
host-key: /path/to/home_ed25519
authorized-agents:
- id: vps-a
public-key: "ssh-ed25519 <AGENT_PUBLIC_KEY>"
proxies:
- name: VPS-REVERSE
type: ssh-reverse
server-ref: home-entry
agent-id: vps-a
VPS agent 侧实现
1. 使用独立的 Ed25519 私钥向 Mihomo 认证,并固定校验 Mihomo 的 SSH 主机公钥。
2. 启动 8 个连接 worker ,各自维护一条 SSH 长连接,具有独立槽位编号。
3. 实现心跳、连接超时及带随机抖动的指数退避重连。
4. 接收 Mihomo 主动打开的自定义 Channel ,解析目标地址;域名由 VPS 解析。
5. 在 VPS 上拨号连接目标 TCP 服务。拨号成功后接受 Channel ,失败则拒绝 Channel ,并返回明确错误。
6. 在 SSH Channel 与目标 TCP 连接之间进行双向数据拷贝,正确处理 EOF 、半关闭、完整关闭和异常退出,及时释放连接、goroutine 及并发配额。
并发与性能设计
每条 SSH 长连接都支持多个业务 Channel ,每个 Channel 对应一条被代理的 TCP 连接。因此,8 条 SSH 长连接可以承载远超 8 条的业务并发连接。agent 提供可配置的全局通道上限,默认 4096 ,由全部 SSH 连接共享,并计入正在拨号的请求。
多条 SSH 长连接用于分散加解密负载,并减少单条底层 TCP 发生丢包时的影响范围。单条业务连接固定使用一条 SSH 长连接,不进行跨连接拆包或聚合;同一 SSH 连接中的 Channel 仍然共享底层 TCP 的队头阻塞。
加密优先采用 [email protected] ,适合具有 AES 硬件加速的设备。SSH 使用标准协议握手,但不应宣称其协议头能保证绕过网络审查。
实现时要特别注意:单个业务 Channel 的取消或超时,不应直接关闭共享 SSH 长连接,也不能通过修改底层 TCP deadline 来影响其他 Channel 。 日志应明确区分 SSH 会话建立与断开、目标拨号失败,以及单个业务 Channel 的正常关闭或传输错误