该技术不同于传统的加密+中转的形式,这个项目用了全新的思路,就是直接修改发送的数据包,这也可以说是目前GFW的一个漏洞吧。

技术背景

  TLS 握手时会发送 SNI(可以理解为域名),用于帮助单 IP 多站点的服务器实现 HTTPS。但加密型 SNI(如 ESNI 和 ECH)尚未普及,且防火墙会直接对此采取 TCP RST 阻断措施,所以目前 SNI 都是明文形式。
  明文 SNI 会暴露你访问的网站域名,因此防火墙采取域名黑名单机制便可以屏蔽对应网站,较少直接屏蔽 IP。
  传统的解决方案,便是利用正常的服务器进行中转传输。

新思路实现

  PhantomSocks 利用 WinDivert(Windows)、Pcap、RawSocket(Linux) 修改 TCP 帧,伪造部分帧参数。修改后的 TCP 帧不合常理,会使大部分防火墙的审查功能紊乱,无法正常进行 SNI 检测,也就不会发出 RST 阻断连接。
  概括来说,可以突破被 DNS 污染的网站。
  等等,这不是修改 TCP 帧吗?应该通用性很强吧?实则不然,TCP 阻断只是众多封禁方法的一种,这些情况不适用:

  • 其他传输层协议。如 UDP 丢弃,DCCP QoS 等。
  • 基于 TCP 的下层协议审查。如应用层的 HTTP 明文检测,后续传输依然会被 RST 阻断。
  • 顶层协议封锁。如网络层 IP 黑名单,除非找到可用的 IP。

更多技术细节见论文:https://conferences.sigcomm.org/imc/2017/papers/imc17-final59.pdf

下载安装

全平台版本

https://github.com/Macronut/phantomsocks
对外提供一个无加密 & 可选认证的代理接口(Socks5、HTTP、SS)供其他软件连接使用,或 Redirect 重定向所有流量。
编译安装:go get github.com/macronut/phantomsocks
默认是 Pcap 模式,RawSocket 和 Windivert 模式的编译及跨平台交叉编译请参见 README,本文不再赘述。

Windows 衍生版(TCPioneer)

https://github.com/Macronut/TCPioneer
直接接管网卡,全局代理。Releases 中有预编译程序。

【知识点】TCP 协议帧头结构

Source port | 源端口
Destination port | 目标端口
Sequence number | 帧序号
Acknowledgment number | 应答号
Data offset | 偏移量
Reserved | 保留备用
Flags x 9 | 9个标志
Window size | 窗口大小
Checksum | 校验和
Urgent pointer | 紧急指针

为了能正常传输 TCP 帧,有一些帧参数是不可修改的。PhantomSocks 可伪造的 TCP 帧参数包括:

  • SEQ number 帧序号
  • ACK number 应答号
  • Checksum 校验和
  • Urgent pointer 中的 timestamp 时间戳
  • Flags 标志中的 SYN 标志(可选,用于 TCP 快速开启,0-RTT)
  • Destination port 目标端口(可选,仅用于传输层的 HTTP 80 重定向 HTTPS 443)
  • MD5(准确的说属于报文段结构,非帧结构)

同时为了保证网络层能正确转发 IP 数据包,PhantomSocks 还可以同时修改 IP 包:

  • TTL 生存时间
  • Destination IP 及 Version(可选,仅用于强制 IPv4 或强制 IPv6)

这里提供一段我标注了注释的配置文件作为参考,更多参数详见项目 README。

# 日志等级
log=5

# TCP 帧伪造方法。伪造 MD5 校验。
method=w-md5

# 指定 DNS 解析服务器,用于解析未手动提供 IP 的域名
server=tls://1.0.0.1:853

# 重置 TCP 帧伪造方法,本行以后的域名生效。更正为伪造 MD5 校验、伪造帧序号、开启强制 HTTPS
method=w-md5,s-seg,https

# 指定相关域名未封禁的 IP
google.com=172.253.114.90,172.217.203.90,172.253.112.90,142.250.4.90,142.250.9.90,172.253.116.90,142.250.97.90,142.250.30.90,142.250.111.90,172.217.215.90,142.250.11.90,142.251.9.90,108.177.122.90,142.250.96.90,142.250.100.90,142.250.110.90,172.217.214.90,172.217.222.90,142.250.31.90,142.250.126.90,142.250.10.90,172.217.195.90,172.253.115.90,142.251.5.90,142.250.136.90,142.250.12.90,142.250.101.90,172.217.192.90,142.250.0.90,142.250.107.90,172.217.204.90,142.250.28.90,142.250.125.90,172.253.124.90,142.250.8.90,142.250.128.90,142.250.112.90,142.250.27.90,142.250.105.90,172.253.126.90,172.253.123.90,172.253.122.90,172.253.62.90,142.250.98.90

# 下列子域及泛解析皆使用上述未封禁 IP
ajax.googleapis.com=[google.com]
.google.com=[google.com]
.google.com.hk=[google.com]
.googleusercontent.com=[google.com]
.ytimg.com=[google.com]
.ggpht.com=[google.com]
.gstatic.com=[google.com]
.translate.goog=[google.com]
blogspot.com=[google.com]
.blogspot.com=[google.com]

# 某些域难以找到未封禁 IPv4,则可以用 SNI 代理中转(龟速)
sniproxy=78.129.226.64,43.255.113.231,43.255.113.229,178.255.46.176,67.222.65.2,69.162.113.194,204.12.225.226,87.117.205.40,69.162.113.198,69.28.83.244,5.152.185.10,213.183.56.23,69.28.82.253,178.209.51.200,78.129.226.113,31.200.241.28
dns.google=[sniproxy]
.googlevideo.com=[sniproxy]

# 本地有 IPV6 的话亦可以强制走 IPv6。不手动提供 SNI 代理和 IP,将由 DNS 提供 IPv6
# ipv6=true
# .googlevideo.com

启动 PhantomSocks

全平台版本

Linux(pcap&rawsocket):
sudo ./phantomsocks -device eth0 -socks 0.0.0.0:1080

Windows(windivert):
phantomsocks -socks 0.0.0.0:1080

macOS:
./phantomsocks -device en0 -socks 127.0.0.1:1080 -proxy socks://127.0.0.1:1080

# 或者重定向网卡流量,Linux 要先用 iptables 重定向。

Linux(pcap&rawsocket):
iptables -t nat -A OUTPUT -d 6.0.0.0/8 -p tcp -j REDIRECT --to-port 6
./phantomsocks -device eth0 -dns :53 -redir :6

Windows(windivert):
./phantomsocks -redir 0.0.0.0:6 -proxy redirect://0.0.0.0:6