问题背景
开启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原理解析
预备知识
IP:用于网络中定位一台主机。端口:定位主机内特定服务
SSH 默认监听22端口,Web服务器监听80(HTTP)或443(HTTPS)端口
应用层协议:数据包就算发送到目标主机的对应端口,也还必须要求监听该端口的服务必须能解析该数据包的格式。
如果向一个期待 TLS 加密报文的 Web 服务器发送明文的 SSH 握手报文,通信会被直接阻断
公网代理节点的安全策略:机场代理节点为防止被SSH暴力破解等安全问题,禁止用户通过代理节点对外建立目标端口22的连接,仅放行80、443等常用网页浏览端口。
TUN模式:TUN工作在OSI第三层的网络层,会接管物理主机所有应用流量,并利用Fake-IP等机制重定向DNS响应,修改数据包原本的路由路径
Fake-IP机制:当本地应用发起DNS解析请求,代理软件拦截该请求,并瞬时返回一个伪造IP(默认CIDR为
198.18.0.1/16),应用之后向该伪造IP发送请求,代理软件本地维护伪造IP <->域名的映射表。域名会根据代理软件的
Rules进行规则匹配,以此判定决定谁来发起DNS解析操作如:
google.com主流Rules都认为走代理节点,本地代理客户端将数据加密发送至远程代理节点,远程代理节点执行DNS解如:
baidu.com则直连,由本地主机的代理客户端做DNS查询
根据以上预备知识
当直接在TUN模式执行
git push,SSH客户端默认连接github.com的22端口,但TUN会劫持SSH的应用层流量,转发到代理服务器,根据预备知识3,该数据包被丢弃,导致连接在传输层被关闭(即报错Connection closed by 198.18.0.42 port 22)那么如果将目标端口改为443,尝试去连接
github.com,根据预备知识2,github.com的物理服务器在443端口运行的标准Web服务器,无法识别SSH客户端发送的SSH-2.0-OpenSSH...这样的纯文本协议标识,因此连接被关闭但GitHub 官方专门提供了一个独立域名
ssh.github.com。该域名对应的服务器的443端口专门绑定了sshd(SSH守护进程),因此将目标主机配置为HostName ssh.github.com并且 端口为Port 443,即可以绕过代理节点的防火墙,又完成了与Github应用层的SSH协议握手但由于TUN的Fake-IP机制,会给同一个域名动态分配不同的虚假IP,频繁IP变动会使
known_hosts校验失败,致使连接阻断。因此需要将SSH客户端的应用层流量转为
SOCKS5代理格式并交给本地代理监听端口,越过TUN网卡的DNS伪造。这里使用ProxyCommand nc -X 5 -x 127.0.0.1:7898 %h %p
最终运行结果:
git push
Everything up-to-date