-
Notifications
You must be signed in to change notification settings - Fork 77
如何适配站点
我们需要先调查墙使用了何种检测/封锁方式,然后才能对症下药。有时是同时使用了多种检测/封锁方式,需要按照顺序检查并应用相应的对策。
在下面,我们假设无法访问的网站为sub.example.com
。
浏览器在建立连接前,需要先将域名解析为IP地址,这是通过查询DNS服务器完成的,因此墙可以返回一个错误的结果。
以Windows系统为例,在命令提示符中运行如下代码可以得到解析的IP地址:
nslookup sub.example.com
可以到如ip138等网站查询这一IP地址的归属,如果查到的是如Facebook等与sub.example.com毫无关系的归属,说明遭到了DNS污染。
为了解决DNS污染,我们需要网站得真实IP地址。在能访问 https://dns.google 等网站的情况下,我们可以去这些网站查询真实IP地址。或者也可以观察 https://ping.chinaz.com 等网站的境外结果变相得到真实IP地址。
在得到真实IP地址的情况下,我们可以修改系统中的hosts文件然后尝试通过浏览器直接访问(需要注意,如果浏览器开启了如DNS-over-HTTPS (DoH) 等加密DNS协议,有可能忽略hosts文件,需要手动配置)。
或者也可以通过curl测试,如假设上面得到真实IP为1.2.3.4
,则可通过如下命令测试:
curl https://sub.example.com --resolve "sub.example.com:443:1.2.3.4" -v
如果能正常访问,则可以通过配置hosts或DNS-over-HTTPS(DoH)、DNS-over-TLS(DoT)等加密DNS协议来访问。这种情况就不需要使用Accesser(尽管因为Accesser自带加密DNS也是可用的)。
如果出现“无法建立安全连接”、failed to receive handshake, SSL/TLS connection failed
等错误,那么很可能就是遇到了SNI RST,这就需要使用Accesser。
在现在流行的TLS协议中,建立连接过程的client hello没有被加密,其中的server_name字段就是域名,易被识别,然后墙会发出TCP RST以结束连接。
除了上面的测试外,如果您懂的如何抓包,可以观察到在客户端发出client hello后马上收到TCP RST(而不是正常的TLS错误)。 进一步地,可以往其他境外IP地址发送包含sub.example.com
的client hello也会出现TCP RST。
为了解决TLS握手未加密的问题,互联网工程任务组(IETF)先是提出了Encrypted Server Name Indication (ESNI),然后又提出了Encrypted Client Hello (ECH) 作为TLS的一个新扩展。
目前,ECH尚未大规模应用,新的浏览器开始支持,但可能需要手动开启,同时需要配合上文提到的境外DoH使用。请自行搜索自己浏览器的设置方法。
HTTP/3是基于UDP的,因此不会被RST。但现在浏览器一般会先尝试HTTP/2,然后依据Alt-Svc
尝试升级。DNS SVCB/HTTPS是解决方案。
在RFC文档中指出,server_name
字段并非必须的,而是可选项,因此我们可以选择不发送server_name
,这就是Accesser目前的原理。
为了使用Accesser,如果您使用PAC来进行代理,可以在PAC文件(如果工作目录中没有这个文件,可以从 https://github.com/URenko/Accesser/blob/master/accesser/pac 下载)中仿照其中的内容添加example.com
(需要尤其小心文件中的逗号):
...
"wikipedia.org": 1,
"example.com": 1
};
如果不便使用PAC代理,或只是想做一个简单的测试,可以使用curl:
curl https://sub.example.com -x https://localhost:7654 -v --insecure
此时可能成功,说明已经可用!
也可能在Accesser的控制台中观察到这样的错误,如:
("hostname 'sub.example.com' doesn't match either of '*.abc.xyz', '123.abc.xyz', 'abc.xyz'",)
说明服务器返回的HTTPS证书并不和sub.example.com
,我们可以在config.toml
中设置check_hostname = false
(不推荐)。
或者我们可以在'*.abc.xyz', '123.abc.xyz', 'abc.xyz'
中挑选一个没被墙的域名,如abc.xyz
,然后用abc.xyz
作为校验用的域名(由于一般sub.example.com
和abc.xyz
是有关联的,如同属一家公司,因此安全性可以保障),可以在rules.toml
中[alter_hostname]
字段添加一条规则:
"sub.example.com" = "abc.xyz"
需要注意,这里添加的abc.xyz
不仅会作为校验用的域名,也会作为server_name
在client hello中发送,这就是要求这个域名没被墙的原因(一般总能找到)。
还有一种情况,sub.example.com
使用了CDN,而CDN一般需要server_name
来识别是何网站,因此我们需要发送这一网站别的可接受的server_name
,这也是通过[alter_hostname]
字段配置,具体见rules.toml
中的例子。如果没有合适的server_name
(例如Cloudflare),应当考虑前面提到的更好的技术(ECH、HTTP/3)。
- 有可能出现网站的部分IP地址无法连接,如维基媒体。这时Accesser内置的DNS返回的IP不一定能连接,此时需要配置
rules.toml
中的[hosts]
字段指定IP地址。 - SNI不一定用于TCP RST,也可能用于间歇性的丢包,如GitHub,这一问题不易确认清楚,但也可先配置好Accesser使用一段时间观察效果。