SSH在TUN模式下失效解决方案
疑难杂症 SSH Git Clash Network 6

问题背景

开启Clash TUN模式后,Git通过SSH向Github推送代码失败
报错如下:

 git push                                                
Connection closed by 198.18.0.42 port 22
致命错误:无法读取远程仓库。

请确认您有正确的访问权限并且仓库存在。

修复目标:使SSH模式的 git push功能能在TUN模式下正常执行

解决方案

修改~/.ssh/config文件:

Host github.com
    HostName ssh.github.com
    User git
    Port 443
    IdentityFile ~/.ssh/Asus-Arch   # 请改为您在Github上公钥对应的私钥路径
    ProxyCommand nc -X 5 -x 127.0.0.1:7898 %h %p

原理解析

预备知识

  1. IP:用于网络中定位一台主机。端口:定位主机内特定服务

    • SSH 默认监听22端口,Web服务器监听80(HTTP)或443(HTTPS)端口

  2. 应用层协议:数据包就算发送到目标主机的对应端口,也还必须要求监听该端口的服务必须能解析该数据包的格式。

    • 如果向一个期待 TLS 加密报文的 Web 服务器发送明文的 SSH 握手报文,通信会被直接阻断

  3. 公网代理节点的安全策略:机场代理节点为防止被SSH暴力破解等安全问题,禁止用户通过代理节点对外建立目标端口22的连接,仅放行80、443等常用网页浏览端口。

  4. TUN模式:TUN工作在OSI第三层的网络层,会接管物理主机所有应用流量,并利用Fake-IP等机制重定向DNS响应,修改数据包原本的路由路径

    1. Fake-IP机制:当本地应用发起DNS解析请求,代理软件拦截该请求,并瞬时返回一个伪造IP(默认CIDR为198.18.0.1/16),应用之后向该伪造IP发送请求,代理软件本地维护伪造IP <->域名的映射表。

    2. 域名会根据代理软件的Rules进行规则匹配,以此判定决定谁来发起DNS解析操作

      • 如:google.com主流Rules都认为走代理节点,本地代理客户端将数据加密发送至远程代理节点,远程代理节点执行DNS解

      • 如:baidu.com则直连,由本地主机的代理客户端做DNS查询

根据以上预备知识

  1. 当直接在TUN模式执行git push,SSH客户端默认连接github.com的22端口,但TUN会劫持SSH的应用层流量,转发到代理服务器,根据预备知识3,该数据包被丢弃,导致连接在传输层被关闭(即报错Connection closed by 198.18.0.42 port 22)

  2. 那么如果将目标端口改为443,尝试去连接github.com,根据预备知识2,github.com 的物理服务器在443端口运行的标准Web服务器,无法识别SSH客户端发送的SSH-2.0-OpenSSH... 这样的纯文本协议标识,因此连接被关闭

  3. 但GitHub 官方专门提供了一个独立域名 ssh.github.com。该域名对应的服务器的443端口专门绑定了sshd(SSH守护进程),因此将目标主机配置为HostName ssh.github.com 并且 端口为Port 443 ,即可以绕过代理节点的防火墙,又完成了与Github应用层的SSH协议握手

  4. 但由于TUN的Fake-IP机制,会给同一个域名动态分配不同的虚假IP,频繁IP变动会使known_hosts校验失败,致使连接阻断。

  5. 因此需要将SSH客户端的应用层流量转为SOCKS5代理格式并交给本地代理监听端口,越过TUN网卡的DNS伪造。这里使用ProxyCommand nc -X 5 -x 127.0.0.1:7898 %h %p

最终运行结果:

 git push
Everything up-to-date

作者
温眸
发布于
更新于
许可