鉴于境外技术网站经常有河蟹出没,所以有必要折腾一下。
关于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博客,转载请保留作者和出处,谢谢。