鉴于境外技术网站经常有河蟹出没,所以有必要折腾一下。
关于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]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|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博客,转载请保留作者和出处,谢谢。