当网络是通过一个透明代理或者一个全局代理之后再访问外部网络时,可能会需要特别定制DNS。这样就能实现“该直连的直连,该代理的代理”的效果。
在开始具体优化前,如果没了解过CoreDNS的朋友可以先看看《CoreDNS自建安全的DNS server》了解一些基本操作。
约定名词
在设定目标之前,出于各方面考虑,先约定以下后面会用到的名词:
内网
。内网就是内部网络,别想多了,就是企业内网。外网
。外网就是外部网络。别想多了,就是一般家庭电信就能上的网。代理服务器
。指内网
的那一台服务器。如果是路由器做透明代理的话,就是指那一台路由器。远端服务器
。指处于外网
的那一台服务器。直连
。直接连接。默认是指代理服务器
识别到是内网
资源后,不通过远端服务器
直接连接。代理
。与直连
相反。
实现目标
- 评判该
代理
还是该直连
的依据是DNS解析出来的IP。 远端服务器
只负责转发,无须DNS解析,以提高性能。- 对于该
代理
或直连
的,DNS的结果应该和外网
或内网
的DNS解析结果一致。
目标的价值
对应3个目标,这里给出相应的3个理由:
- 首先这里不希望通过域名区分转发与否。因为各种域名太多了,网上的list只能维护常见域名。而对于其他域名往往不能很好的处理。而对于已经开始动手搞透明代理的玩家来说,通过域名区分比ip段来说准确度感觉有点低了。
- 既然采取了以IP作为代理与否的区分点,那么
代理服务器
做一次DNS解析是不可避免的。而对于一个请求,显然没有必要做两次解析(除非是为了校验)。因此远端服务器
是不应该解析DNS的。 - 既然DNS的解析完全在
代理服务器
进行。那么就要求代理服务器
要同时亲和内网
和外网
的CDN(我也不知道为什么企业内网
会有CDN)。
实现思路
DNS解析的地理影响
首先我们必须认识到,DNS的解析是和DNS请求发送者的地理位置息息相关的。
以B站为例,在新加坡和美国分别用nslookup
在8.8.8.8
上解析www.bilibili.com
得到的结果分别是:164.52.28.62
和148.153.46.90
。
因此想要准确的获得内网
和外网
的DNS解析结果,就必须要分别在内网
和外网
解析域名。
DNS的合并
当我们拿到一个域名的时候,我们并不清楚这个域名是该直连
还是该走代理
。而DNS解析的时候也是一样,我们其实并不能预先知道这个域名应该从内网
还是从外网
解析。
因此我的做法是两边都解析,然后根据两边的结果共同判断采取哪边的结果。如果内网
的解析结果指向一个内网
ip,那么就以内网
解析结果为准。如果内网
的解析结果指向外网
ip,那么就以外网
解析结果为准。
具体工具我没有找到别人造好的轮子,所以就自己造了一个:https://github.com/xloypaypa/dns-relay。不算太圆,但是还能用,主要配置脚本要用Clojure写。可以参考example,然后改改config拿来用(我记得默认就是按照上一段的合并逻辑配置的)。
缓存
不论如何,这样跨地域的解析,以及复杂的合并逻辑将导致每次DNS的解析效率变得较低。因此,在合并逻辑和最终用户之间,还需要一个CoreDNS来做一层缓存。这一层缓存能够大大的提高使用体验。
最终结构
其结构和我那个不圆的轮子里的example类似。
左上角的to 114
是部署在内网
的CoreDNS,右上角的to 8
是部署在外网
的CoreDNS。
中间红色的DNS-relay
就是合并内网
和外网
的工具。最下面的CoreDNS就主要负责缓存合并结果。这两个东西具体部署在哪里都可以,取决于在哪里查询,一般是部署在路由器上。
使用效果
延迟
就个人的使用体验来说,每天刚刚下班回家,所有缓存都已经失效的时候,的确能感受到延迟,大概一次解析需要300ms左右。
不过解析是并行的,所以对于一个网站来说,其实不用心体会,其实也感觉不出太大的差别。尤其是在已经运行操作了一段时间之后,几乎感觉不到任何的差别。
访问体验
访问体验个人感觉是非常好的。因为判断完全是自动的,我完全不需要思考这个站到底是在我内网
还是外网
。
我们都知道内网
的防火墙是双向的,而这个解析的规则却始终是固定的。因此即使我现在出差在外,访问体验和我在家也没有任何区别。
这意味着,我认为我已经真正的跨了过去,因为他已经完全对我没有影响了。
虽然仍然是个威胁
通过这种方式,我们相当于实现了一个按照一定规则合并两个上游DNS记录的自己的DNS server。从而辅助了网络代理配置的自动化和透明化。