应用程序级代理和DNS污染解决方案
由于此问题的本质复杂性以及对解决问题所需的前置知识的要求,这注定无法成为一个手把手的教程。我认为这里已经提供了足够多的信息,需要它们的人应该能自己学会如何把它们组装起来,从而能够变通地解决衍生问题。
Windows上的应用程序级代理
应用程序代理方案:Proxifier
目前没有一个应用程序级代理的解决方案优于Proxifier,恐怕在未来很长一段时间内也是如此,因此实施此方案需要你购买Proxifier。我建议购买Proxifier的标准版而不是便携版,因为在Linux上使用Proxifier等需求需要标准版才有的功能。
在创建Proxifier代理规则时,普遍有两种模式:
- 1.默认通过直接连接,通过规则代理特定类型的连接。
- 2.默认通过代理连接,通过规则让特定类型的连接直连。
建议在此选择默认通过代理连接,通过规则直连的模式。这是因为在实际需求中,可以直连的连接往往是可以在事前确定的,反过来则不可行,至少无法完美实现。至此,问题可以被简化为如何创建“让特定类型的连接直接连接”的规则。
手动为Proxifier创建直连代理规则是可能的,但由于需要创建的规则数量之多,很快就会超出人力的极限,从而逐渐变得不可行。这是很多Proxifier用户使用另一种模式的原因,但如上文所述,另一种模式是无法完美实现的,因此我们需要直面这一模式的困难。
直连代理规则生成器:ppx-inject
ppx-inject是我编写的用于向Proxifier的规则配置文件自动注入基于地区的直连规则的CLI程序。
ppx-inject能够自动从区域互联注册管理机构(RIR)下载最新的数据,然后将特定地区的IP地址范围设置为Proxifier的直连规则。由于数据是即时下载的,这比任何自带IP地址数据库的软件都可靠:你很难知道那些自带IP地址数据库的软件用的数据库是否过时,但ppx-inject可以确保在注入规则时使用的总是最新的数据。当你需要更新IP地址数据库时,只需要重新运行一次命令。需要注意的是,在使用基于IP的规则时,需要关闭Proxifier的通过代理解析DNS服务器的功能。
ppx-inject之所以以地区为基础建立规则,是因为我需要解决的问题在事实上没有其他更有效的基础。使用ppx-inject建立的规则会导致所有非直连地区的连接都走代理,这可能不是每个人想要的结果,但它是人力成本最低,且最具有实用意义的方案。你总是可以如法炮制出你需要的直连代理规则生成器,但不一定会比基于地区的方法有意义。
代理服务器硬切换:gost
Proxifier有一个缺点,是它缺少硬切换代理服务器的功能,即当你切换代理规则时不会断开之前建立的所有连接。我询问过作者是否可以在未来加上这个功能,作者无法给出任何保证。因此这部分职责我们交给gost完成。
gost可以为多个SOCKS代理实现负载均衡。实际使用中,在客户端这一侧对代理服务器实现负载均衡意义不大,因为信道的品质不一致,而自动化评估信道品质由于成本过高几乎不可能实现。在此我们只是借助负载均衡器所必然具有的转发功能来实现代理服务器的硬切换,具体原理很简单:编写对应的cmd脚本,在执行脚本时,杀死现有gost进程(届时,所有已建立的连接都会断开),再按新的转发参数启动新的gost进程。在使用gost的情况下,Proxifier只需连向gost的端口,实际使用的代理服务器后端由gost的启动参数决定。
解决DNS污染
当DNS遇上事实核查:fcdns
解决DNS污染的主流方案是像ChinaDNS这样的方案,然而使这些方案成立的基础不够扎实,所以我写了自己的。
fcdns是一个DNS转发器,将DNS查询以一定的规则转发给下级DNS。fcdns与主流方案区别在于它通过我称为“投毒检测”的事实核查机制来判断域名是否被污染。通过搭配IP地址白名单,fcdns就可以决定一个DNS查询应该被转发给“缓慢但具有正确性的可信信道”还是“快速但可能被污染的不可信信道”。
fcdns的具体原理在项目主页有比较详细的描述,简单来说,它建立在当前“向非DNS服务器发出DNS查询也会收到DNS回答(来自投毒者的抢答)”这一事实上。即使这个污染策略改变,使用fcdns的用户也至少可以得到一份已被污染的域名清单,这总是比预定义的清单更真实有效。
值得一提的是,通过在ppx-inject和fcdns上共用相同的IP地址范围,可以确保连接总是得到最佳的DNS查询结果。
建立可信信道:CoreDNS
CoreDNS被我用于建立fcdns使用的本地可信信道,可信信道的根基是像DNS over HTTPS或DNS over TCP这样的协议。这些协议在现实世界中相当脆弱,因为公共DNS服务器很容易识别和屏蔽,但只要配合Proxifier,就可以绕过限制。
使用CoreDNS的原因在于它很简单,其配置文件在处理此类需求时很容易编写,并且具有缓存功能。
代理Windows上的Linux虚拟机
过去多年使用Linux桌面发行版的经历告诉我,永远不要将Linux作为桌面系统来使用。如今,我在桌面端使用Linux的唯一方式是在VMware里安装LTS版本的Ubuntu Server,然后让VMware使用Proxifier的代理,本节的内容都是以此为前提的。
你可能会想知道我做出以上判断的依据,毕竟对Linux平台来说似乎还有很多条路可以走。我的确试图写这些内容,但遗憾的是将这些对我来说像常识一样的经验提取成论据的成本太高了。
在Linux上使用Proxifier
Linux上没有Proxifier,也没有同等规格的替代方案,所以这里的Proxifier指的是Windows上的Proxifier。在实施完Windows上的解决方案时,事实上已经做完了让Linux使用Proxifier的大部分准备。虚拟机应该以NAT方式联网,这样它的网关就是Windows系统,我们不需要手动配置DNS选项,因为它使用的就是Windows的DNS——如果你解决了Windows上的DNS污染,就不需要再在Linux上再做一遍。
为了能够代理VMware的连接(即
vmnat.exe
),Proxifier需要比VMware更早启动,要实现这一点,Proxifier需要以服务的形式运行。Proxifier提供了Service Mode以实现此需求,此模式的缺点是不能以GUI的形式配置Proxifier,在配置前需要先手动退出Service Mode。所幸,上文建立的Proxifier规则不怎么依赖手动添加额外规则,并且切换代理服务器并不需要Proxifier,因此Service Mode对使用这套解决方案的人来说影响相当之小。由于Proxifier代理的是VMware,因此它对Linux来说并不是应用程序级代理方案:Proxifier可控制的最细粒度是目的IP而不是进程名,但这也已经够用了,因为大多数需要应用程序级代理的程序都已经在Windows上处理完了。即使有Proxifier无法满足的需求,也可以通过graftcp这样的程序在Linux上针对性地解决。