应用程序级代理和DNS污染解决方案

由于问题的本质复杂性,对解决问题所需的前置知识的要求,这无法成为一个手把手的教程。我在此已经提供了足够多的信息,真正需要它们的人应该能自己学会如何把它们组装起来,并且能够变通地解决衍生问题。

Windows上的应用程序级代理

应用程序代理方案:Proxifier

目前没有一个应用程序级代理的解决方案优于Proxifier,恐怕在未来很长一段时间内也是如此,因此实施此方案仍然需要购买Proxifier。建议购买Proxifier的标准版而不是便携版,因为在Linux上使用Proxifier等需求需要标准版特有的功能。

在创建Proxifier代理规则时,普遍有两种模式:

  1. 1.

    默认直连,通过规则代理特定类型的连接。

  2. 2.

    默认代理,通过规则让特定类型的连接直连。

我们在此选择默认代理,通过规则直连的模式。这是因为在实际需求中,可以直连的连接是可以事前确定的,反过来则做不到。至此,问题可以被简化为如何创建“让特定类型的连接直连”的规则。

手动为Proxifier创建直连代理规则是可行的,但需要创建的规则数量之多,很快就会超出人力的极限。这是很多Proxifier用户使用另一种模式的原因,如上文所述,另一种模式是不完美的,因此需要我们直面困难。

自动创建直连代理规则:ppx-inject

ppx-inject是我编写的用于向Proxifier的规则配置文件自动注入基于地区的直连规则的CLI程序。

ppx-inject能够自动从区域互联注册管理机构(RIR)下载最新的数据,然后将特定地区的IP地址范围设置为Proxifier的直连规则。由于数据是即时下载的,这比任何自带IP地址数据库的软件都可靠:你很难知道那些自带IP地址数据库的软件用的数据库是否过时,但ppx-inject可以确保在注入规则时使用的总是最新的数据。当你需要更新IP地址数据库时,只需要重新运行一次命令。

ppx-inject之所以以地区为基础建立规则,是因为事实上没有其他更有效的基础。使用ppx-inject建立的规则会导致所有境外连接都走代理,这可能不是每个人想要的结果,但它是人力成本最低,且最具有实用意义的方案。

在使用基于IP的规则时,需要关闭Proxifier的通过代理解析DNS服务器的功能。

代理服务器硬切换:gost

Proxifier有一个缺点,是它缺少硬切换代理服务器的功能,即当你切换代理规则时不会断开之前建立的所有连接。这部分职责我们交给gost完成。

gost可以为多个SOCKS代理实现负载均衡。实际使用中,在客户端这一侧对代理服务器实现负载均衡意义不大,因为信道的品质不一致,而自动化评估信道品质由于成本过高几乎不可能实现。在此我们只是借助负载均衡器所必然具有的转发功能来实现代理服务器的硬切换,具体原理很简单:编写对应的cmd脚本,在执行脚本时,杀死现有gost进程(届时,所有已建立的连接都会断开),再按新的转发参数启动新的gost进程。在使用gost的情况下,Proxifier只需连向gost的端口,实际使用的代理服务器后端由gost的启动参数决定。

解决DNS污染

具有事实核查能力的DNS转发器:fcdns

解决DNS污染的主流方案是像ChinaDNS这样的方案,然而使这些方案成立的基础不够稳定,所以我写了自己的。

fcdns基于另一套行事方式,它通过我称为“投毒检测”的事实核查机制来判断域名是否被污染,通过IP地址白名单来分流未被污染的查询(白名单是以与ppx-inject相同的方式得来的),从而决定一个DNS查询应该被转发给“缓慢但具有正确性的可信信道”还是“快速但可能被污染的不可信信道”。

fcdns的具体原理在项目主页有比较详细的描述,简单来说,它建立在当前“向非DNS服务器发出DNS查询也会收到DNS回答(来自投毒者的抢答)”这一事实上。即使这个污染策略改变,使用fcdns的用户也至少可以得到一份已被污染的域名清单,这比现有的任何其他DNS反污染方案都有用。

配合Proxifier和ppx-inject(通过共用相同的IP地址范围),fcdns可以确保连接总是得到最佳的DNS查询结果。

可信信道DNS转发器:CoreDNS

CoreDNS被用于建立fcdns使用的本地可信信道,可信信道的根基是像DNS over HTTPS或DNS over TCP这样的协议。这些协议在现实世界中相当脆弱,因为公共DNS服务器很容易识别和屏蔽,但只要配合Proxifier,就可以绕过限制。

使用CoreDNS的原因在于它很简单,它的配置文件在处理此类需求时很容易编写,并且具有基于缓存功能。也可以选择架设其他的DNS服务器程序,只要它能够向可信信道转发DNS查询就行。

代理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对使用这套解决方案的人来说影响相当之小。

开启Service Mode有一些前提条件,以Proxifier 4来说,需要标准版才能使用Service Mode,并且在安装许可证时需要安装到整个计算机上,这些在官方文档里都有说明。

由于Proxifier代理的是VMware,因此它对Linux来说并不是应用程序级代理方案:Proxifier可控制的最细粒度是目的IP而不是进程名,但这事实上也已经足够够用了,因为大多数需要应用程序级代理的程序都已经在Windows上解决了。即使有Proxifier无法满足的需求,也可以通过graftcp这样的程序在Linux针对性解决。