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 | (msg) -> |
从一个Buffer中读取前2个字节,客户端和服务器分别开一个循环队列,记录下最近的 X 个请求,如果找不到对应的则丢弃
测试结果
从原理上这个程序可以完全防止GFW的DNS投毒攻击,但是如开头所述,UDP包丢包率非常高,甚至有可能发送40,50个包后服务器端一个都收不到的情况,因此目前还无法使用,下一步可能考虑预先打开TCP连接等等方式,测试下延迟是否有明显增加。
推荐阅读
如果对GFW工作原理等内容有兴趣的话,推荐阅读以下一些文章,本人也从中得到了大量的知识与灵感,在此一并感谢。