众所周知,最近墙长个了.昨晚 @danyanpi 跟我叨咕: VPN 的 DNS 若设置成 8.8.8.8 ,则结果被污染.其实以前亦是如此,墙会污染几个著名的公共 DNS .询问我解决方案,这个本来我不太清楚,因为一直用 SSH + PAC , DNS 解析是远程的,所以并不会遇到这种情况.但他说,难道你就不能 XXXX 么?

我暗忖:

  • 现在都午夜了, RFC 是个大坑,搞这个会繁琐死.弄不好会折腾到天亮都未必能解决.不能搞.
  • 反正自己也不会碰到,何必和猪打架.不能搞啊.
  • 折腾这个就是浪费时间和精力,一毛钱不赚,不能搞啊啊啊…

结果,妈蛋,好奇心不止会害死猫,我也没忍住,还是搞了!结果有些出乎意料,写出来和大家分享.

首先是收集资料,和 DNS 相关的 RFC 有十几个,这大坑.

然后就是挑选工具.虽然很多人对 Bash 推崇备至,可是我对它真心打怵,每次写起来比便秘痛苦多了.所以还是用 Ruby 吧…

接着看看 Ruby 中有关 DNS 的库,果然标准库中有 “resolv.rb” .整整 2400 行.

最后设计实验方案:

检测公共 DNS 的污染情况,包括 UDP(默认) 和 TCP(可选) .按照以前的说法是墙不会污染 TCP .

尝试除了加密以外的其它方式解析 DNS .

这里只说说怎么解决 Ruby 中默认不提供 TCP requester的问题.官方的处理逻辑是这样的:先通过 UDP 请求.失败了再通过 TCP 请求.

可是这不符合我们实验的要求,要不怎么说啊,歪果仁(外国人)太单纯,他哪知道可怜的中国猿类要面对这么复杂的网络环境.此刻凯撒附体(来自于猩球崛起),来给 Ruby Standard Library 打个猴子补丁( Monkey patch )吧~

下面是代码与真相时间:

最后公布结论:

  1. 功夫网已经进化,会同时污染 UDP / TCP 方式的 DNS 查询.
  2. 功夫网似乎不再像以往一样固定返回若干假 IP ,而变得随机返回结果.这导致以往收集假 IP 来过滤的方法无效了.
  3. DNS 的污染是基于端口(53端口),所以可以请求非标准端口的 DNS 服务器.
  4. 非标准端口无论是 UDP 还是 TCP 都可以获得正确结果,因此使用 UDP 还能快些.