iptables劫持并拦截DNS查询53端口实现转向(Redirect)

!本文可能 超过1年没有更新,今后内容也许不会被维护或者支持,部分内容可能具有时效性,涉及技术细节或者软件使用方面,本人不保证相应的兼容和可操作性。

企业内网中经常会有这样的需求,比如说业务服务器的IP地址为192.168.6.25,大家也就习惯于访问这个地址了,运维也很厚道的将某个域名解析到这个IP地址,这样大家也就不必记住繁琐的IP地址,同时运维也很方便的将业务服务器由192.168.6.25的主机迁移到192.168.6.26的主机而无需通知客户端更改地址,这也是域名发挥的作用,好了,现在问题来了:-)

客户说我们企业很小,不想另外购买域名,好吧,每年五十几块也是一笔费用,而且购买域名后还需要有人维护,比如要记得续费什么的,略麻烦。同样的还觉得将内网地址公布到外网上不是安全的行为。

经过我的询问得知该企业拥有一台自建的DNS服务器,为全网提供DNS查询,那这事情就好办多了,对DNS服务器软件硬绑定指定的域名到IP地址的记录(由于是我们自己的DNS服务器,这里的域名可以任意设置,当然最好设置为公网上没有的域名地址以避免冲突)。

对于DNSMASQ,直接在/etc/dnsmasq.d路径下建立一个conf文件,比如server.conf,内容如下:

address=/business.server/192.168.6.25

这里business.server为我们任意设置的域名,而192.168.6.25为指向的IP地址。

由于这里局域网上网的路由DHCP自动分配DNS服务器为我们的内网服务器,所以对于自动获取IP和DNS的客户端则不需要我们多操心,但是问题远远没有解决,如果有人自己指派了DNS服务器呢?

好吧,运维人员可不希望一个一个去通知用户修改DNS服务器为指定的内网服务器,但是通过强大的iptables我们可以神不知鬼不觉地劫持用户的所有DNS查询。

当然这里的iptables是在路由上设置的(这里局域网的路由是一台小型的服务器,运行着Linux系统),众所周知,DNS使用53端口,并通过TCP或者UDP协议传输,那么我们就需要劫持这两个协议传输通过53端口的查询流量到我们指派的DNS服务器上。

iptables -t nat -A PREROUTING -i ethX -p udp --dport 53 -j DNAT --to $(get lan_ipaddr)
iptables -t nat -A PREROUTING -i ethX -p tcp --dport 53 -j DNAT --to $(get lan_ipaddr)

这里ethX为局域网的LAN口,而$(get lan_ipaddr)指示的是我们自己的DNS服务器(一般在内网),比如我们的LAN口为eth1,而DNS服务器位于192.168.6.10,则上述规则更改为:

iptables -t nat -A PREROUTING -i eth1 -p udp --dport 53 -j DNAT --to 192.168.6.10
iptables -t nat -A PREROUTING -i eth1 -p tcp --dport 53 -j DNAT --to 192.168.6.10

好了,到这里我要介绍的也就完了,但是这种办法有个前提是在局域网内,所有的流量必须走路由器,也就是这个路由器为网关型路由(所有流量进出口),否则此办法无效,但对于特殊情况可以考虑采取类似的DNS投毒方式进行,我也没试过,这边也不介绍了。这种方法还有问题,应用上述防火墙规则会导致所有发往53端口的udp或者tcp数据流量被截获,如果某外网服务器53端口做其他用处则会异常,同时在一定程度上也加重了自建DNS服务器的负担,如果自建服务器崩溃,则所有的DNS解析将会失效。

当然,我今天讲的这个技巧还有一个应用场景,比如在网络环境比较恶劣的情况下,DNS被攻击或者遭到投毒,自建服务器可以通过多种手段避免这些安全问题,这样为了局域网安全,转移DNS查询流量则是必须的了。

若无特别说明,本网站文章均为原创,原则上这些文章不允许转载,但是如果阁下是出于研究学习目的可以转载到阁下的个人博客或者主页,转载遵循创作共同性“署名-非商业性使用-相同方式共享”原则,请转载时注明作者出处谢绝商业性、非署名、采集站、垃圾站或者纯粹为了流量的转载。谢谢合作!

    • 一般这种是网络防火墙提供的功能,大部分完备的防火墙软件均可以提供端口拦截和转发,对于Windows下企业级防火墙可以考虑采用ISA或者TMG实现。

  1. 很有趣,但是我的不成功。

    我是在学着你的文章//wangye.org/blog/archives/845/假设了Raspberry pi 路由器,在路由器上输入
    iptables -t nat -A PREROUTING -i wlan0 -p udp –dport 53 -j DNAT –to 192.168.6.10
    iptables -t nat -A PREROUTING -i wlan0 -p tcp –dport 53 -j DNAT –to 192.168.6.10
    无法做到劫持,希望得到你的解答,谢谢

    • 很凑巧,我也在树莓派上做过这个实验,结果是成功的,最终的效果是无论查询的DNS服务器是否存在,响应结果的服务器必定是指定的。
      我不太明白你的相关配置,值得注意的是确保命令是正确的,比如dport前面是两个短横线等等,还有就是192.168.6.10这个DNS服务器是否存在并正常运行DNS服务:

      iptables -t nat -A PREROUTING -i wlan0 -p udp --dport 53 -j DNAT --to 192.168.6.10
      iptables -t nat -A PREROUTING -i wlan0 -p tcp --dport 53 -j DNAT --to 192.168.6.10
      
      • 成功了,谢谢。

        我试了下这样劫持DNS的话,DNS服务器返回DNS包的dest_ip是路由器的地址,而非客户端ip地址,客户端会把这样的DNS包丢掉。

        还有奇怪你的博客的评论没有email提醒机制,我以为你一直没有回复呢orz

        • 不客气,这种拦截只有在查询DNS经过拦截网关服务器时才能生效,如果本地客户端的话会直接进入回环而不经过拦截服务器。
          Email主要考虑到博客服务器的资源消耗所以没有开,毕竟垃圾评论太多,带来不便还请见谅。

请稍后...

发表评论

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

*