使用dns2tcp搭建DNS隧道

0x00 问题场景

假设有如下图所示的问题场景。

问题场景

办公电脑通过防火墙与互联网相连,防火墙被配置为仅允许DNS数据通过。在此场景下,办公电脑显然无法直接访问互联网。现在我们想做的是通过使用dns2tcp建立DNS隧道,使得办公电脑可以访问互联网。

许多大学的校园网在连接后,打开浏览器会自动跳转到身份认证页面。在认证前,是无法访问互联网的,但一般来说,其DNS解析是可用的。这便是上述问题场景中的一个实例。另一个实例是有些公司的网络出口处有防火墙阻止了普通员工的办公电脑访问互联网的,但有时防火墙的配置会允许DNS数据通过。

0x01 预备知识

我们假设读者对DNS有最基本的了解,若不了解可先阅读《百度百科:DNS》。这里要介绍的是NS记录。以下内容摘自《阿里云-用户指南-记录类型》。

NS 记录

(1)什么情况下会用到NS记录?

如果需要把子域名交给其他DNS服务商解析,就需要添加NS记录。

(2)NS记录的添加方式

记录类型为NS。

主机记录处填子域名(比如需要将opo.abc.com的解析授权给其他DNS服务器,只需要在主机记录处填写opo即可,NS记录的主机记录(RR值)不能为空,主机记录@不能作为NS记录使用,且NS记录不支持泛解析【将所有子域名解析到同一地址】,授权出去的子域名不会影响其他子域名的正常解析)。

线路类型(默认为必填项,否则会导致部分用户无法解析)。

NS记录值,NS向下授权,请填写DNS域名记录值为要授权的DNS服务器域名,为了保证服务可靠性,建议您添加至少2组DNS服务(例如:ns1.alidns.com, ns2.alidns.com)。

TTL不需要填写,添加时系统会自动生成,默认为600秒(TTL为缓存时间,数值越小,修改记录各地生效时间越快)。

NS记录不是在设置某个域名的DNS服务器,而是在设置某个子域名的DNS服务器。理解这一点对于成功搭建DNS隧道至关重要。

例如我有域名“werner.wiki”,添加NS记录类型的解析,主机记录值为“test”,记录值为“dns.my.com”。则此记录生效后,所有关于“test.werner.wiki”及其子域名的DNS查询,都会找DNS服务器“dns.my.com”。

0x02 原材料

为了成功搭建DNS隧道,我们需要一台位于互联网中的(而不是在防火墙里的)服务器,我们将要搭建的隧道的一头是办公电脑,另一头便是这台服务器。在实践中,我们常常会买一台云服务器或vps来搭建DNS隧道。由于DNS的敏感性,这台服务器最好是在中国大陆。为了进行演示,我买了一台腾讯云的云服务器(刚好有快要过期的代金券~)。

我们还需要一个可以设置解析的域名。这个域名是什么无所谓,只要能设置解析就行。所以可以买一个很便宜的域名,第一年的价格在几块钱。在这篇文章中,我直接使用了自己博客的域名werner.wiki。实际上,域名是非必须的,后文中会解释这一点。

0x03 开始搭建

1 设置域名解析

首先添加一条A类解析,主机记录为“dns”,记录值为“118.xx.xx.120”,这个IP地址就是腾讯云服务器的公网IP地址。

然后添加一条NS解析,主机记录为“dns2tcp”,记录值为“dns.werner.wiki”。

这两条域名解析如下图所示。

域名解析设置

这两条域名解析做了什么?

第一条A类解析是在告诉域名系统,“dns.werner.wiki”的IP地址是“118.xx.xx.120”。

第二条NS解析是在告诉域名系统,想要知道“dns2tcp.werner.wiki”的IP地址,就去问“dns.werner.wiki”。

如何验证域名解析设置是否成功?

在随便一台电脑上ping域名“dns.werner.wiki”,若能ping通,且显示的IP地址是“118.xx.xx.120”,说明第一条A类解析设置成功并已生效。

在腾讯云服务器(118.xx.xx.120)上抓包,抓目的端口是53的udp包,命令是:

tcpdump -n -i eth0 udp dst port 53

53端口是DNS协议使用的端口。注意上述命令中的参数“eth0”,含义是网卡接口名,在不同的服务器中可能不同。

然后在随便一台电脑上运行命令:

nslookup dns2tcp.werner.wiki

这条命令是在对域名“dns2tcp.werner.wiki”进行查询。如前所述,若我们设置的域名解析生效,则对此域名的DNS查询,会最终被转发到“dns.werner.wiki”,而“dns.werner.wiki”的IP地址是“118.xx.xx.120”,也就是我们的腾讯云服务器上的的公网IP地址。

查看腾讯云服务器上的抓包情况,若抓到对域名“dns2tcp.werner.wiki”进行查询的DNS请求数据包,则说明第二条NS解析设置成功并已生效。

抓到的数据包如下图所示。图中的目的IP地址是腾讯云服务器的内网IP地址,所以我没有打码。

抓到的DNS查询数据包

2 服务器端软件配置

我买云服务器时选择了Ubuntu16.04系统。以下操作均只针对此系统。其他操作系统原理相同,细节可能有所出入。

安装配置dns2tcp

在腾讯云服务器上,我们首先需要安装dns2tcp,命令如下:

sudo apt-get install dns2tcp

我安装的版本是v0.5.2。安装完成后打开配置文件“/etc/dns2tcpd.conf”,将其中内容修改为:

listen = 0.0.0.0
port = 53
user = nobody
chroot = /tmp
domain = dns2tcp.werner.wiki
resources = socks:118.xx.xx.120:7777

在修改配置文件前可以先备份原有配置文件。关于此配置,需要说明的第一点是监听IP地址应该为“0.0.0.0”,而不是“127.0.0.1”,否则就只能监听到本地连接;第二点是域名(domain)是NS解析对应的域名;第三点是dns2tcp中的资源(resources)不是dns2tcp自带的,需要自己动手实现。在我给出的配置文件中只写了一个名为“socks”的资源,其IP地址是云服务器公网IP,端口号是我随手敲的。这个资源是一个socks代理,我想要实现的是办公电脑通过DNS隧道后直接连接到一个socks代理上,使用此代理访问互联网。

安装配置dante-server

现在让我们来搭建一个socks代理。我选择使用dante-server来搭建。首先安装它,命令如下:

apt-get install dante-server

我安装的版本是v1.4.1。安装完成后打开配置文件“/etc/danted.conf”,将其中内容修改为:

logoutput: /var/log/sockd.log
internal: eth0 port = 7777
external: eth0
socksmethod: username none
user.privileged: proxy
user.unprivileged: nobody
client pass {
    from: 0.0.0.0/0 port 1-65535 to: 0.0.0.0/0
}
socks pass {
    from: 0.0.0.0/0 to: 0.0.0.0/0
    protocol: tcp udp
}

在修改配置文件前可以先备份原有配置文件。原有配置文件对各配置项的含义与作用有充分的说明,此处不再赘述。我们现在看到的配置文件配置了一个监听端口7777的socks代理,无身份认证,允许任何客户端连接。

3 客户端软件配置

办公电脑便是这里所说的客户端。若办公电脑是Ubuntu系统,直接运行如下命令即可获得dns2tcp的客户端程序dns2tcpc:

    sudo apt-get install dns2tcp

若办公电脑是Windows系统,可以点此下载dns2tcp客户端程序dns2tcpc的Windows版。

0x04 搭建隧道

现在终于可以搭建隧道了。

首先在服务器上运行如下命令来启动socks代理:

/etc/init.d/danted start

然后在服务器上运行如下命令来启动dns2tcp的服务器端:

dns2tcpd -f /etc/dns2tcpd.conf -F -d 2

其中参数“-f /etc/dns2tcpd.conf”指定了配置文件,“-F”要求程序在前台运行,“-d 2”指明了输出调试信息,级别为2。作为首次运行,我们加上参数“-F”和“-d 2”。

最后,在办公电脑(客户端)上运行如下命令以建立DNS隧道:

dns2tcpc -r socks -z dns2tcp.werner.wiki -l 8888 -d 2

其中参数“-r socks”指明了要连接的资源,“-z dns2tcp.werner.wiki”指明了建立DNS隧道使用的域名,“-l 8888”指明了隧道的这头监听的端口,“-d 2”的作用和服务器端相同。

至此,隧道搭建完成。

0x05 测试

在办公电脑(客户端)里打开火狐浏览器,设置socksv5代理,IP地址是“127.0.0.1”,端口是8888,如下图所示。

设置火狐浏览器代理

然后用百度搜索“IP”,看到显示当前办公电脑IP地址为“118.xx.xx.120”,如下图所示。

用百度搜索“IP”

这说明DNS隧道搭建成功,实现了办公电脑访问互联网的目标。

0x06 其他

若是前面各步均正确无误,最后出现了错误:

No response from DNS xx.xx.xx.xx

那么可能的原因是中途某个DNS服务器丢弃了TXT类型的奇怪DNS查询请求。如何解决这一问题呢?其实只要我们能绕过中途那台DNS服务器就好了。但问题是我们不知道问题出在哪里,中途有哪些DNS服务器我们也是不知道的。所以一个简单的办法就是绕过中途所有的DNS服务器,把办公电脑的DNS直接设置为“118.xx.xx.120”。这固然是可行的,但还有更简单的办法,我们可以在dns2tcpc的参数中指明要使用的DNS服务器,命令如下:

dns2tcpc -r socks -z dns2tcp.werner.wiki dns.werner.wiki -l 8888

直接指明以“dns.werner.wiki”为DNS服务器,办公电脑发出的DNS查询直接指向“dns.werner.wiki”,不再经过原有DNS服务器转发。这样我们实际上完全抛开了现有的域名系统,也就没有了注册域名设置解析的必要。但若防火墙规则较为严格,只允许目的IP是特定DNS服务器的数据包通过,此方法便行不通了。

0x07 总结

我是在上周五开始尝试用dns2tcp搭建DNS隧道,到这周六才成功。中途几经波折,差点就放弃了。看来做事还是得有锲而不舍的精神,不能轻易放弃。

刚开始只是照着网上的教程搭建,以为自己是明白其中的原理的。若是没有遇到什么问题,顺顺利利地就搭建成功了,便也就失去了学习了机会。直到遇到了难以解决的问题,在网上找不到解决方法时,才只好自己去研究,尝试弄清楚事物的运作原理。只有知道了运作原理,才能定位问题、解决问题。记得《如何思考》一书中也讲到,弄清楚事物的运作原理是进行聪明思考的前提。

其实我在几年前就看到过DNS隧道的文章,当时觉得原理很简单,以为自己全都明白,要搭一个也就是分分钟的事。但现在真正动手去做,才发现并不简单。正应了古人所说“纸上得来终觉浅,绝知此事要躬行”。

12 Replies to “使用dns2tcp搭建DNS隧道”

  1. 作者有没有遇到开启了dns2tcp监听后连接不上的问题?
    客户端 nslookup dns2tcp.域名结果如下:
    ;; connection timed out; no servers could be reached

    服务端启用dns2tcp后:
    03:36:29 : Debug options.c:97 Add resource socks:127.0.0.1 port 8888
    03:36:29 : Debug socket.c:55 Listening on 0.0.0.0:53 for domain ns1.aa.com
    Starting Server v0.5.2…
    03:36:29 : Debug main.c:132 Chroot to /tmp
    03:36:29 : Debug main.c:142 Change to user nobody
    浏览器用代理访问出现如下结果:
    Creating session id: 0xd1f8 address = 123.216.128.227 (compression NOT wanted)
    03:36:41 : Debug auth.c:60 Ask for resource ‘socks’
    03:36:41 : Debug socket.c:183 Connecting to 127.0.0.1 port 8888
    Error socket.c:189 connect error

    客户端监听:
    :$ dns2tcpc -r socks -z ns1.yroot.win dns.aa.com -l 8888 -d 2
    debug level 2
    Listening on port : 8888

    浏览器使用代理结果如下:
    When connected press enter at any time to dump the queue
    Debug session.c:46 Request challenge
    Debug session.c:53 Challenge = ‘I9RS5L4T0GV1QGB9’
    11:36:41 : Debug session.c:54 Session created (0xd1f8)
    Debug session.c:77 Sending response : ‘A651DFFC6BAC85FE47D9D96BC64DE8539FB857F4’ (key = (null))
    11:36:41 : Debug auth.c:94 Connect to resource “socks”
    Error : Connexion refused

    1. 你好。你说的问题我没有遇到过,但有一点想法和你分享。

      客户端 nslookup dns2tcp.域名,解析失败是正常的。具体原因见NS记录的含义。
      资源socks不是dns2tcp提供的,需要你自己实现。我尝试在服务器上关闭了提供socks资源的dante-server,然后在客户端连接DNS隧道,浏览器使用代理访问网页,出现了和你一样的错误:Error : Connexion refused。所以请检查资源socks。

  2. 老哥, win10得问题我会了!!但是nslookup dns2tcp.werner.wiki 在这一步的时候它提示我server can’t find dns2tcp.zhaoyanxue.tk: SERVFAIL这个问题,我是按照一步一步操作的啊,不知道该咋整了,希望老哥能帮帮我

  3. 校园网强制使用了一个DNS 也就是说在客户端执行dns2tcp时假如不指定dns就会用学校自己的DNS解析 而学校自己的DNS解析不到我的dns2tcp.XXX的域名 这种情况有解吗

  4. 您好,按照您的指导安装了dns2tcp,也启动了dns2tcp
    但是在使用的时候显示认证失败是什么原因?

    Debug session.c:46 Request challenge
    Debug session.c:53 Challenge = ’98YELKLSCMQ2SIMZ’
    Debug session.c:54 Session created (0xf094)
    Debug session.c:77 Sending response : ‘F7C8D508DA5B139DEDAEDA694209A54EBB2636F6’ (key = (null))
    Debug auth.c:94 Connect to resource “socks”
    Error : Authentication Failed

回复 Werner 取消回复

您的电子邮箱地址不会被公开。 必填项已用*标注

18 − 2 =