OpenWRT路由器unbound+dnsmasq解决DNS污染与劫持

出处:http://blog.csdn.net/conupefox/article/details/8557253

 

鉴于境外技术网站经常有河蟹出没,所以有必要折腾一下。

 

关于DNS劫持和DNS污染的概念和区别,就不多说了。网上都有很多解释。解决方案无非就几种。

 

1.使用非53的udp端口。这个方法显然不具备实操意义,好少有开放非53UDP端口的dns服务器。

2.使用TCP 53端口查询,其中google的8.8.8.8就支持

3.使用加密的DNS协议,opendns貌似提供了解决方案。

 

查了一下openwrt有提供unbound这个软件包,可以非常方便地部署到路由器上。

unbound支持使用TCP协议进行DNS查询,所以只需要把DNS请求用TCP协议转发出去境外的DNS,就可以解决污染问题了。

虽然DNS的协议规定TCP协议也是其可以使用的协议,一般软件发出都是UDP 53端口来,所以需要做一个UDP转TCP的DNS转发器。

利用Openwrt里面自带了dnsmasq就能实现了。以下是实现方法。

 

先下载unbound。

[plain] view plaincopy

  1. opkg update
  2. opkg install unbound

需要注意的是,如果使用Dreambox,他提供的unbound版本过低,不能提供TCP转发功能。我已提交了patch给Dreambox项目了,不过貌似项目管理者太繁忙没有处理这个任务单….

https://dev.openwrt.org.cn/ticket/84#

如果在Dreambox强行安装trunk或者Attitude Adjustment提供的unbound,会有lib依赖的问题,无法正常使用。

所以要么就不要用Dreambox,要么就按照我那个任务单里面说的方法把新版的unbound移植过来并编译Dreambox,十分折腾,呵呵。

 

由于dsmasq使用了udp53端口,所以unbound要换成另一个端口,我这里改成5353,然后打开tcp-upstream选项,意思是使用TCP协议转发请求至上游DNS。

安装完成之后,编辑unbound的配置文件/etc/unbound/unbound.conf,加入或找到相应的行去掉注释。

[plain] view plaincopy

  1. port: 5353
  2. tcp-upstream: yes
  3. forward-zone:
  4.         name: “.”
  5.         forward-addr: 8.8.8.8
  6.         forward-first: no

 

把unbound设置成开机启动,然后启动unbound

[plain] view plaincopy

  1. /etc/init.d/unbound enable
  2. /etc/init.d/unbound start

接下来配置dnsmasq,编辑dnsmasq的配置文件/etc/dnsmasq.conf,把指定的域名转发到unbound,用unbound进行解析。一行一个域名例如,

  1. server=/xxx.com/127.0.0.1#5353

 

把被污染掉的域名加进去就可以了,重启dnsmasq生效。

此外还要配置dnsmasq的默认转发DNS地址,普通的dns请求继续用udp协议转发到运营商的DNS就可以,这样才能保证国内CDN网站正常使用,如下图。

 

google上面有几个项目都可以获取到最新的污染域名列表,在这就不详细说了,哈哈。自己写了个脚本取下来,并通过计划任务定时更新,基本上都可以解决污染问题了。

以下放出脚本,具体不解释,该懂的都懂,需要使用完整版的wget。小tips:使用IPV6连接google code获取列表会方便很多。

make_dnsmasq_conf.sh

[plain] view plaincopy

  1. #!/bin/ash
  2. #Anti DNS Pulltion
  3. #make dnsmasq.conf
  4. #Script By D2O
  5. #
  6. #v0.1 2012/8/13
  7. #v0.2 2012/11/17
  8. local DNS_DIR=/tmp/dns
  9. local DNSMASQ_CONF=$DNS_DIR/dnsmasq.conf
  10. wget –no-check-certificate -O $DNS_DIR/gfwlist.txt https://autoproxy-gfwlist.googlecode.com/svn/trunk/gfwlist.txt
  11. wget -O $DNS_DIR/smarthosts http://smarthosts.googlecode.com/svn/trunk/hosts
  12. echo please wait…
  13. echo ##Anti DNS Pulltion >$DNSMASQ_CONF
  14. $DNS_DIR/getlist.py $DNS_DIR/gfwlist.txt >>$DNSMASQ_CONF
  15. #rm gfwlist.txt
  16. #cp $DNSMASQ_CONF /etc/
  17. /etc/init.d/dnsmasq reload

getlist.py,修改自网上大牛的脚本。

 

[python] view plaincopy

  1. #!/usr/bin/env python
  2. #   Aug 19 2011
  3. #   Copyleft@2011 Published Under BSD Lisense
  4. #           Ronald Liu
  5. #   [email protected]
  6. #   FYI  http://lzsblog.appspot.com/%3Fp%3D291001
  7. #   
  8. #   Mod By D2o 2012/8/13
  9. #   http://conupefox.csdn.net
  10. import sys,re,base64
  11. def splitList(txt):
  12.     arr = txt.split(“n”)
  13.     pattern =‘^([01]?dd?|2[0-4]d|25[0-5]).([01]?dd?|2[0-4]d|25[0-5]).([01]?dd?|2[0-4]d|25[0-5]).([01]?dd?|2[0-4]d|25[0-5])$’
  14.     l = []
  15.     for line in arr:
  16.         if (not len(line)): #empty line
  17.             continue
  18.         if (line[0] == “!”): #Comment line
  19.             continue
  20.         elif(line[0:2] ==“@@”):#Forbidding line
  21.             continue
  22.         elif(line.find(“/”)!=-1 or line.find(“*”)!=-1 or line.find(“[“)!=-1 or line.find(“%”)!=-1 or line.find(“.”)==-1 ): #URL is ignored, only domains left
  23.             continue
  24.         elif(re.search(pattern, line)):#IP address
  25.             continue
  26.         #In this case, domain name is irrelevant to protocol(http or https)
  27.         elif(line[0:2] ==“||”):
  28.             l.append(line[2:])
  29.         elif(line[0] == “.”):
  30.             l.append(line[1:])
  31.         else:
  32.             l.append(line)
  33.     return l
  34. #Decode and decorate the input string
  35. f = open(sys.argv[1],“r”)
  36. txt = f.read()
  37. txt = base64.decodestring(txt)
  38. domains = splitList(txt)
  39. per_line=””
  40. forwarddns=“127.0.0.1#5353”
  41. for line in domains:
  42.     if (line!=per_line):
  43.         print “server=/” + line + “/” + forwarddns
  44.     per_line=line

 

 

Enjoy!!

原文首发CSDN博客,转载请保留作者和出处,谢谢