FabricPath

通过 ssh 反向隧道搭梯子,经过长期验证

  •  
  •   FabricPath · 14h 11m ago · 2075 views

    需要国内有公网 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 的正常关闭或传输错误
    
    22 replies  •  2026-10-31 00:43:51 +08:00
    hanfengzxh
        1
    hanfengzxh  
       13h 44m ago via Android
    有了 ai 可以自己实现封装协议,又稳又安全。
    FabricPath
        2
    FabricPath  
    OP
       12h 29m ago
    @hanfengzxh 我没试过其他非标协议。如果我去搞 gfw 的话,看到非标准流量特征,且长期 SrcIP 单一、连接 cps 搞、带宽大,会考虑直接掐掉。
    其实正向连接大家都玩不出啥花儿了,gfw 也不需要太复杂的策略,如果一个目标 IP 常年有入站请求,并且 src ip 很单一,那很容易就可以判定为是梯子了。
    现在反向连接审查得少,我估计纯粹是因为国内家宽有公网的不多。
    zizon
        3
    zizon  
       12h 1m ago
    可能你直接 ssh tunnel 也一样.
    tcp 层面你还是点对点 tcp 流量特征.

    可能只是因为有公网 IP,更接近出口层,GFW 信道/侧信道反而更少.
    yeyeye
        4
    yeyeye  
       11h 34m ago   ❤️ 2
    ssh -d 算是最早的梯子了,甚至无需服务器端有单独的软件,本身就是 ssh 服务器标准功能( ssh 自带的功能其实挺多的,proxy 、端口转发[类似 frp]……)。

    稳定了一段时间,后来通通被检测特征,限速,断开连接。然后大家都放弃了这种方式。。

    从特征来说,ssh 发送的命令通常都很小数据包(低频,上行包很小,下行数据量很少,小概率使用 scp 互传文件才会有大一点的数据),对比之下,梯子的特征太明显(包大小、时序、频率等等)。

    豁免?当年人家第一个干掉的就是 ssh 隧道啊。。

    而且反向由国外连国内,也是在检测内的。


    唯一有可能性的就是大量开发 ssh 协议的应用,使得 ssh 协议失去“专用协议”的特征,慢慢的无法准确检测,才可能放松。

    当然我不是说完全不能用,你都使用了,效果在这里,肯定暂时是可用的,只是真不适合大范围使用,特征太过于明显了。。。现在的梯子,普遍是把自己伪装成正常流量。

    而且 ssh 协议最多用于控制服务器,直接给你来一个限速,正常使用 ssh 管理服务器其实也能用,对所有人的影响很小。。这也是为什么大家早期放弃这个方式的原因,太过于局限了。
    nekoyaki
        5
    nekoyaki  
       11h 33m ago
    ssh 隧道我估计是看接入链路中的某个环节, 我在 2014 年左右就开始用它,印象里大约到 2015 或者 16 年,就发现已经没法用了,会被定向封端口,或者会被严重干扰速度。
    当时还有一个 obfuscated ssh 项目,是 fork 了一个很老版本的 ssh ,增加了混淆手段,用这个会稳定很多, 但因为 ssh 隧道自身一个 tcp 连接,有时候还容易“假死”,比如进程还在但端口监听没了, 或者 ssh 断了会导致整个链路断掉,之类的很多情况,所以我后来只把它当备用隧道方案了。 再后来这个工具也不维护了,我就没有继续用它了。
    nomansky
        6
    nomansky  
       11h 24m ago
    古早的梯子技术。ssh 特征这么明显,没被封只是你运气好而已。
    est
        7
    est  
       11h 19m ago
    稳定?稳定是别人没拿你当 KPI 刷。。。。
    FabricPath
        8
    FabricPath  
    OP
       10h 27m ago
    @est 你自己实现协议不就是为了特征少吗,因为国内没多少人有公网 IP ,所以只是检测重点不在这里;如果要检测梯子流量,那太容易了,只要二元组流量过大、连接数过多,直接掐了就行了。
    @nomansky 就是因为特征明显才猜测临时进了豁免通道,并且 ssh 建连接的频率极低,也比非 mux 情况下的新建连接数量少得多;非公开协议,那太明显了。
    @yeyeye 就是因为国内有公网的少。相比伪装成正常的流量,之前最开始灰度接反向 ssh 的时候,和走 cloudfront 的正向连接做负载均衡,开会的时候会直接基于二元组封禁到 cloudfront 接入点 IP 的连接(不清楚非公网 IP 是否也会使用二元组封禁),但是 ssh 隧道还活着。

    此外基于 gfwreport 过去几年的报告来看,gfw 审查模型多检测连接前 N 个报文,对于超长时间的长连接来说,没明显感知到会中途检测的情况。包括之前使用 mux 的时候,也观察到新建连接超时,存量连接能正常通信的情况,不过没定量评估正向长连接的稳定性,纯感觉。

    @zizon 正向的 ssh tunnel 和其他协议一样,只能跑到 400Mbps ,速度明显会低一截。
    est
        9
    est  
       9h 21m ago
    @FabricPath 自己实现协议特征少是一方面,特征杂是另一方面。

    比如以一千个人有一千种协议。这样 KPI 刷起来就没那么痛快

    一千个机场一种协议,一次性可以刷个大的 KPI

    站在对方的视角思考问题。
    FabricPath
        10
    FabricPath  
    OP
       7h 37m ago
    @est 我关心对方 kpi 干嘛,被封了就继续用 cdn 接入就行了,本来家宽有公网就少,提供一个思路和测试结果而已,不知道你要杠啥。
    crc8
        11
    crc8  
       7h 13m ago
    我是从 SSH 转到 SS 来的。
    v2gba
        12
    v2gba  
       6h 48m ago
    我记得反向是严打目标

    good luck
    lymanbernadette6
        13
    lymanbernadette6  
       6h 46m ago
    文艺复兴..
    xeonforce
        14
    xeonforce  
       6h 40m ago via Android
    这给我干哪年来了,虽然这个方式还在内网开发上还常用,但拿来翻属实过于文艺复兴了..临时用用还行,以前会封端口的
    leaflxh
        15
    leaflxh  
       6h 35m ago
    快进到某天 OP 发帖:《服务器登不上去了》
    FabricPath
        16
    FabricPath  
    OP
       6h 2m ago
    @leaflxh 过去 5 、6 年一直用同一个 lightsail ,就今年流量大升了规格才换了 IP ,只有开大会的时候会短时间掐二元组。

    @xeonforce 放到过去靠二元组流量特征去无脑掐的年代,这种模式容易被识别,放到现在,从泄露的 gfw 代码来看,中心都放到去扫描前 N 个报文的特征,而且 gfw 用的 dpdk ,dpdk 本身要做包缓存就需要消耗巨量的 hugepage ,不做包缓存又解决不了 SNI 分片。

    从 gfw repo 的论文也能看出来,gfw 是对连接做了缓存的,并且在高峰期还会降级
    vicalloy
        17
    vicalloy  
       5h 43m ago
    早期用 ssh 隧道,被封的速度都是以分钟算的。
    被封后等一段时间可以解封,没敢头铁继续用。
    FabricPath
        18
    FabricPath  
    OP
       5h 41m ago
    顺便补充一下为啥我会用反向的连接,因为去年粗略扫了一遍 tsg 的源码,发现他主要审查的方向是 tls 、quic ,并且从文档和已有的规则集来看,具备明显的境内->境外和境外->境内方向性,审查重点就是境外往境外主动发起的 tls 和 quic 。
    但是并没有发现“长连接”,“二元组”等明显的规则,从过去几年只有特殊时期才封二元组来看,这应该是一个 adhoc 的规则集,平时不会启用。

    至于为什么是 ssh ,纯粹是因为懒得做实验,ssh 比 frp 更像是正常流量,并且启用之后一直很稳定,也没动力去探索其他协议。
    虽然从代码中也没找到明确豁免 ssh 的逻辑,但是从性能测试来看,使用反向的 ssh 会明显比正向的 ssh 隧道更快,且可以稳定复现,说明至少现在部署的 gfw 版本,大概率对两个方向的处理有差异。
    FabricPath
        19
    FabricPath  
    OP
       5h 39m ago
    https://geedge.report/assets/geedge-tsg-usenix26.pdf 附上今年的研究报告。
    cr3bit
        20
    cr3bit  
       4h 10m ago
    身边统计学:裸 ssh 配置改着改着 client_loop: send disconnect: Connection reset ,不套一层什么 overlay 根本没规律的断
    MarkLeeyun
        21
    MarkLeeyun  
       2h 42m ago
    这是在干啥。。我经常用 reverse 连接局域网和另一个局域网。不过这个延迟够么? tcp 上面的是不是延迟偏高啊
    ronman
        22
    ronman  
       3 mins ago
    @hanfengzxh #1 大隐隐于市才是真的,非标一抓一个准
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1945 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 58ms · UTC 16:47 · PVG 00:47 · LAX 09:47 · JFK 12:47
    ♥ Do have faith in what you're doing.