出处: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。
- opkg update
- 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,加入或找到相应的行去掉注释。
- port: 5353
- tcp-upstream: yes
- forward-zone:
- name: “.”
- forward-addr: 8.8.8.8
- forward-first: no
把unbound设置成开机启动,然后启动unbound
- /etc/init.d/unbound enable
- /etc/init.d/unbound start
接下来配置dnsmasq,编辑dnsmasq的配置文件/etc/dnsmasq.conf,把指定的域名转发到unbound,用unbound进行解析。一行一个域名例如,
- 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
- #!/bin/ash
- #Anti DNS Pulltion
- #make dnsmasq.conf
- #Script By D2O
- #
- #v0.1 2012/8/13
- #v0.2 2012/11/17
- local DNS_DIR=/tmp/dns
- local DNSMASQ_CONF=$DNS_DIR/dnsmasq.conf
- wget –no-check-certificate -O $DNS_DIR/gfwlist.txt https://autoproxy-gfwlist.googlecode.com/svn/trunk/gfwlist.txt
- wget -O $DNS_DIR/smarthosts http://smarthosts.googlecode.com/svn/trunk/hosts
- echo please wait…
- echo ##Anti DNS Pulltion >$DNSMASQ_CONF
- $DNS_DIR/getlist.py $DNS_DIR/gfwlist.txt >>$DNSMASQ_CONF
- #rm gfwlist.txt
- #cp $DNSMASQ_CONF /etc/
- /etc/init.d/dnsmasq reload
getlist.py,修改自网上大牛的脚本。
- #!/usr/bin/env python
- # Aug 19 2011
- # Copyleft@2011 Published Under BSD Lisense
- # Ronald Liu
- # [email protected]
- # FYI http://lzsblog.appspot.com/%3Fp%3D291001
- #
- # Mod By D2o 2012/8/13
- # http://conupefox.csdn.net
- import sys,re,base64
- def splitList(txt):
- arr = txt.split(“n”)
- 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])$’
- l = []
- for line in arr:
- if (not len(line)): #empty line
- continue
- if (line[0] == “!”): #Comment line
- continue
- elif(line[0:2] ==“@@”):#Forbidding line
- continue
- 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
- continue
- elif(re.search(pattern, line)):#IP address
- continue
- #In this case, domain name is irrelevant to protocol(http or https)
- elif(line[0:2] ==“||”):
- l.append(line[2:])
- elif(line[0] == “.”):
- l.append(line[1:])
- else:
- l.append(line)
- return l
- #Decode and decorate the input string
- f = open(sys.argv[1],“r”)
- txt = f.read()
- txt = base64.decodestring(txt)
- domains = splitList(txt)
- per_line=””
- forwarddns=“127.0.0.1#5353”
- for line in domains:
- if (line!=per_line):
- print “server=/” + line + “/” + forwarddns
- per_line=line
Enjoy!!
原文首发CSDN博客,转载请保留作者和出处,谢谢