摘要

GFW 会通过主动探测来识别运行 Shadowsocks 的服务器. 我们通过实验再次验证了这一结论, 同时我们提供了一种简单且有效的对抗策略: 在服务器端设置白名单防火墙. 实验证明我们的策略有效延长了服务器的生存时间, 而且并不会影响用户的使用体验.

介绍

GFW 的工作原理非常复杂, 但总体而言可以划分为两个步骤, 被动的嗅探和主动的探测. 前者是墙抓取数据包分析流量特征, 从而识别翻墙流量. 后者是主动向翻墙服务器发出探测数据包, 以主动探测来抓取特征并识别翻墙服务器. 目前流行的翻墙软件 (如 Shadowsocks, V2RAy 等) 以防御被动检测为主, 并不能很好地防御主动探测. 一些翻墙软件 (如 ShadowsocksR) 设计了对抗重放攻击的模块 (如使用 nonce), 但实践中运行 ShadowsocksR 的服务器同样会被封禁.

我们猜测 GFW 的工作策略是: 以被动探测筛选服务器, 再以主动探测的结果作为封禁的依据. 这样, 只要我们能够对抗墙的主动探测, 就能够让服务器生存下来. 我们没有针对墙主动探测方式设计防御策略, 而是以源 IP 地址作为依据, Drop 所有的入站数据包, 只保留用户的数据包, 即白名单防火墙策略. 对比不使用这样策略的服务器, 白名单策略使得服务器成功躲过了 GFW 的封禁. 这种策略易于部署, 适用于任何服务器和翻墙协议 (实验中我们尝试了 SS, SSR 和 MTProto), 而且通过巧妙的设计可以不增加用户的负担.

白名单策略

白名单策略是指, 我们通过数据过滤防火墙, 只允许服务器接收特定 IP 来源的入站流量, 而拒绝所有别的流量. 具体而言, 我们 Setup 了两种服务器, 主服务器和子节点: 主服务器负责联络所有的子节点, 子节点负责给用户提供翻墙服务. 用户在翻墙前通过主节点记录自己的 IP, 主节点会把 IP 广播给所有的子节点, 从而把这个特定 IP 加入到白名单中. 这样我们就可以成功避开防火墙的探测.

但是这样操作会给用户带来不必要的负担. 用户的网络环境可能很复杂; 宽带的每次重新拨号, 从 WiFi 环境过度到蜂窝网, 或者在蜂窝网的不同基站之间穿梭都可能会导致 IP 的变化, 从而无法被服务器识别. 为了减轻用户的负担, 我们把 IP 注册功能和 SSR 的订阅更新功能绑定. 用户每次向 SSR 服务器请求订阅列表的时候, 我们会抽取用户的 IP, 然后广播到所有子节点上. 这样的策略大大减轻了用户的操作负担.

简单地丢弃所有入站数据包未免过于粗糙. 事实上我们可以有更灵活的防火墙策略. 经过研究我们发现, 被 GFW 用作主动探测的服务器全部都是 Linux 服务器, 而很多用户使用的操作系统是 Windows. Windows 发出的数据包区别于 Linux 的一大特征是, Windows 数据包的起始 TTL 是 128, 而 Linux 则是 64. 所以一个简单的思路就是, 我们可以无条件信任 TTL 大于 64 的数据包 (考虑到用户到服务器之间的距离不太可能超过 64 跳). 这样 Windows 用户就可以不被防火墙影响.

实践中我们还发现开放 22 端口和接受 ICMP 包并不会导致服务器被墙. 为了避免开启防火墙导致失联, 我们可以考虑开放 ICMP 协议和 22 端口.

实验结果

服务器的生存挑战

我们在我们运营的 SSR 机场的服务器上全部部署了防火墙, 并使用上述策略更新防火墙的白名单. 我们进行了为期 18 天的实验. 在实验中, 所有服务器都没有被墙 (除了一次意外撤除防火墙的事件). 这些服务器工作在 163 线路, CN2 GT 线路和 CN2 GIA 线路. 但是为了保护我们自己的安全, 我们不能公布实验的具体规模.

为了对比, 我们尝试性撤除 4 台服务器的防火墙, 在这几次实验中, 这些服务器在数分钟到一小时之内都被迅速封禁. 这进一步证明了白名单防火墙确实是保护服务器的主要因素.

除了 SSR, 我们还测试了 MTProto 协议. MTProto 是一个早就证明被特征识别的协议. 实验证明, 这样的策略同样可以保护 MTProto. 实验中我们部署了 4 台服务器, 设有保护的两台服务器一直生存至今, 而没有部署防火墙的两台服务器分别在第 20 分钟和第一小时被封禁. 这个实验再次印证了主动探测是墙封禁服务器的必要条件, 即使这个协议早已被特征识别.

探测数据包的分析

关于探测数据包的分析, 这篇文章 已经有较为透彻的分析. 这里我们再次印证了它的一部分结论, 并有小部分新的发现. 我们主要有以下发现:

  1. GFW 探测服务器的源地址处于电信和联通网络, 以联通骨干网为主.
  2. 探测数据包的 TTL 全部小于 64.
  3. 只要有 Shadowsocks 流量记录, 墙会把各种可能的翻墙协议全部探测一次, 包括古老的已经不再适用的协议.
  4. 没有流量记录的端口, 即使在运行 Shadowsocks, 墙也不会探测, 即它不会穷举各种端口.
  5. 墙会用很多地址探测服务器, 但每个地址只会探测一个端口.
  6. 墙对 Shadowsocks 端口的探测频率大约是 10 分钟一次, 探测的概率和这个端口的流量大致呈正比关系, 但是也有一些端口从来没有被探测过 – 我们并不知道为什么.
  7. 每一次探测会持续数分钟, 之后墙不会发起同样的探测.

具体配置方案

我们使用的工具是 iptables. 我们假设用户的 IP 是 1.2.3.4, 具体的配置方案是

 iptables -A INPUT -m ttl --ttl-gt 80 -j ACCEPT
 iptables -A INPUT -p icmp -j ACCEPT
 iptables -A INPUT -p tcp --dport 22 -j ACCEPT
 iptables -A INPUT -i lo -j ACCEPT
 iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
 iptables -A INPUT -s 1.2.3.4 -j ACCEPT
 iptables -P INPUT DROP