通过 IPLC 利用 UDPspeeder 转发 DNS 查询

众所周知,有些场景下 DNS 查询受到污染(或者不严格地说,劫持),返回虚假的结果,比如不存在的域名也解析到广告 IP 地址,或者上游不遵循 TTL 约定胡乱缓存,或者干脆 1.1.1.1 就被劫持为内网 IP 地址等等。这种情况下,我们可能需要自建本地 DNS 服务器,通过可靠信道中转查询。如果你有 IPLC(“国际专线”),可以直接通过 IPLC 转发到公共 DNS 服务器(如 1.1.1.1:53),不过也许可以做得更好。

注意,本文内容不涉及“科学上网”,请勿向本人咨询相关问题。请确保合法应用本文内容,例如使用于公司内网、自有服务器。如无资质,在公网提供公共 DNS 服务涉嫌违规。

既然通过 IPLC,转发到 1.1.1.1:53 当然是可以的,一般情况下不会受到污染。但你仍然可能担心,DNS 标准协议是明文的,公网传输到 IPLC 入口之间还是有可能搞鬼。可以选择 DoH(DNS over HTTPS)、DoT(DNS over TLS)之类的方案,然而这类方案增加协议开销,性能不是特别好,可以说没有发挥 IPLC 的优势。有没有介于其中的方案,既不明文传输,又不要那么强的协议安全性呢?

可以利用 UDPspeeder。UDPspeeder 是一款跨平台双边网络加速工具,用来加速 UDP。经常用于游戏加速。不过既然标准 UDP 查询也基于 UDP(某些情形下也使用 TCP,这里不考虑),当然也能用。UDPspeeder 的核心功能是发送冗余包,降低丢包率;顺带也支持 XOR(异或)加密。于是,如果我们在本地查询端(客户端)和 IPLC 落地端(服务端)用上 UDPspeeder,相比 IPLC 直接转发 DNS 查询,有这样两个好处:

  1. 降低丢包率,提高查询稳定性,在一些情况下能降低延迟;
  2. 简单加密,对抗公网段 QoS 限制或潜在污染,而不显著增加协议开销。

UDPspeeder 安装方法不赘述,参照中文手册。分别在服务器、本地,下载对应平台架构的二进制文件,解压即可。需要 Service 文件等可自行编写。

服务端参数示例:

./speederv2 -s -l0.0.0.0:5533 -r8.8.8.8:53 -k 2QTTHWeAQtkCZINFqbhga62CsBSiXC4c4Y3PEuYYWExvUNfeOnfK2wqKypMG6jRVs4SASAiC9HcwRjIfSXPf25SqOF -f2:2 --timeout 1 --disable-obscure

客户端后部分参数保持与服务端相同,示例:

./speederv2 -c -l127.0.0.1:53 -r1.2.3.4:5533 -k 2QTTHWeAQtkCZINFqbhga62CsBSiXC4c4Y3PEuYYWExvUNfeOnfK2wqKypMG6jRVs4SASAiC9HcwRjIfSXPf25SqOF -f2:2 --timeout 1 --disable-obscure

其中 -k 提供 XOR 加密密钥,请改成自己随机生成的字符串。

-f2:2 --timeout 1 表示引入 <=2ms 延迟,两倍发包。参考项目 wiki。如果环境尚可,-f2:1 应该就够用。

--disable-obscure 设置随意。想减少流量消耗就写上。

这样应该就行了。

示例中加密密钥是 90 字节长的大小写字母、数字混合字符串。请注意,即使我们设定这么长的 XOR 密钥,仍然只能理解为简单加密,或者认为是混淆,并不提供很高的安全性。这是因为假如要实现 XOR 的“完美保密性”,需要密钥长度大于消息长度,并且密钥是一次性的。在这个方案中不太现实。UDPspeeder 源码中给密钥开的数组是 char key_string[1000],但在实际中常常受制于环境限制:比如一些 Windows 程序所支持的路径带参数,不能过长。具体我没有研究,根据自己的情况调整密钥,越长越好。而要求一次性密码本更不方便,可能得对 UDPspeeder 二次开发。退而求其次的做法是定时更换密钥,不是很安全也不是很方便,UDPspeeder 支持 fifo(文件管道)但不能用来动态更改 -k 参数。总而言之,假设你真的在乎这种安全性,为什么还看这种折中方案,不去用 DoH、DoT 呢?

最后,虽然本文提供了一种方案,但更多的是一种思路。因为我没有进行很多测试,有可能关于 QoS 的叙述是错的。诸位应该根据自身实情来选择应用。

全部为采集文章,文中的 联系方式 均不是 本人 的!

发表评论