FQDNS 的初步设计

源代码位于:https://github.com/richard1122/FQDNS

注:由于浙江大学网络与Linode 日本节点的UDP包丢包率过高,本项目目前暂时无法使用,记录下来只为能够留下一些有用的信息。

项目背景

在今年(2015)寒假的时候,我有了开发一个新的翻墙软件的想法,但寒假因为种种原因(主要是拖延),连Github项目都创建好了,却一直没有开始。

近期由于GFW多次升级,特别是DNS污染相关的:

  • 过去,只会返回黑名单内IP的随机一个,因此通过黑名单配合延迟解析 (据说GFW会首先返回一个假的结果,但是真实结果在返回时并不会被drop),可以从一定程度解决这个问题。
  • 现在,从2015年起,DNS开始随机污染,会返回国外的随机IP,或一个非常大的IP列表,且这些IP地址很多都是真实有web服务在运行的。因此无法很好地判断这是一个假的地址了。

因此我决定开发一个同时需要客户端和服务端的DNS程序,将本地的dns请求加密发送到远程服务器,并在解析完成后将结果以加密方式返回,为了保证解析速度,我选择使用UDP。

工作原理

如上文所述,这个的工作原理非常简单,首先在本地监听一个UDP端口,设置下游dns服务器(如DNSMASQ)使用它来解析,然后配置服务器和客户端共享的加密密钥,服务器地址等参数,即可开始运行。

解析阶段

  • 客户端收到一个DNS请求后,将其加密,然后根据地址发送到对应的服务器地址
  • 服务器收到请求后,将数据包解密,然后把raw udp package直接转发给某个DNS服务器(如8.8.8.8)

回复阶段

  • 服务器收到从DNS服务器返回的解析结果后,将其加密,然后发送给来源的客户端
  • 客户端收到来服务器的请求,将其解密,然后转发给来源的请求地址

识别DNS请求

根据rfc1035,DNS请求和返回包的前16位是一个ID,DNS服务器会拷贝请求包的ID来使我们知道这个返回包对应哪个请求,因此我们通过代码

1
2
(msg) ->
return msg.readUIntBE 0, 2

从一个Buffer中读取前2个字节,客户端和服务器分别开一个循环队列,记录下最近的 X 个请求,如果找不到对应的则丢弃

测试结果

从原理上这个程序可以完全防止GFW的DNS投毒攻击,但是如开头所述,UDP包丢包率非常高,甚至有可能发送40,50个包后服务器端一个都收不到的情况,因此目前还无法使用,下一步可能考虑预先打开TCP连接等等方式,测试下延迟是否有明显增加。

推荐阅读

如果对GFW工作原理等内容有兴趣的话,推荐阅读以下一些文章,本人也从中得到了大量的知识与灵感,在此一并感谢。

  1. 翻墙路由器的原理与实现
  2. Chinadns