Total Pageviews

Wednesday, 31 October 2012

用pdnsd缓存DNS查询,解决DNS查询慢的问题

pdnsd是一款高效灵活的DNS proxy服务器,它既可以充当一个DNS forwarding的角色,也可作为一个DNS cache服务器,更可以作为一款简单的本地解释DNS服务器。优点如下:
(1)配置简单灵活,可定时自动检测upstream DNS server的健康;
(2)有CLI用于查看服务器的运行状况,并可在线更新服务器参数而无需重启服务器。
Github地址:https://github.com/udienz/pdnsd

pdnsd, written by Thomas Moestl, is a proxy DNS server with permanent caching (the cache contents are written to hard disk on exit) that is designed to cope with unreachable or down DNS servers (for example in dial-in networking).
The official pdnsd homepage by the original author can be found at http://home.t-online.de/home/Moestl/, but unfortunately pdnsd is no longer being maintained by him. As far as I know I am presently the only one actively working on the code, so if you want the latest features and fixes, this is the place to get them.
主页:http://www.phys.uu.nl/~rombouts/pdnsd.html
配置起来非常简单:
1. 将example配置文件复制一份
2. 将:
server {
label= “myisp”;
ip = 58.215.76.163
IP换成自己的ISP提供的DNS地址,多个用”,”隔开
3. 最重要的一步,许多DNS不接受”ping”测试,所以要将:
uptest=if/ping 改成
uptest=query
4.  将/etc/resolv.con里的nemeserver改成127.0.0.1
PS:
pdnsd.conf是可以控制pdnsd的返回结果的,就是说,可以通过配置pdnsd来达到自定义解析结果的日的。
另外,我们使用pdnsd的根本原因是因为ISP的DNS不稳定,解析慢。pdnsd可以直接从根服务器查询开始,更不必依赖于ISP的DNS。但是需要说明的是,使用了CDN服务的站点,可以会取到不精确的地址,而导致访问速度不佳.
---------------------------------

用pdnsd实现DNS解析加速


你是不是一直受到DNS服务器查询速度太慢的困扰?本文推荐Linux下一款名叫pdnsd的软件,解决这个问题。相比bind和 dnsmasq,pdnsd有一个优点:重启后仍然能记得之前缓存的条目。这对家庭用的计算机来说非常重要,因为不像服务器那样7×24小时开机,所以一 旦关机重开后还需要重新创建缓存的话,加速效果会非常有限。
一、安装
依然使用我最爱的Archlinux为例。pdnsd在community源里,直接安装即可:
pacman -S pdnsd
二、配置
pdnsd附带了一个配置文件示例,直接拷贝一份后,按自己的情况进行修改:
cp /etc/pdnsd.conf.sample /etc/pdnsd.conf
注意修改配置文件的时候别忘了加行末的分号,那是不可省略的。
其中有几项需要按如下修改以提高DNS查询效率:
neg_rrs_pol=on;
par_queries=1;

proxy_only=on;
purge_cache=off;

#可选,把A记录的ttl最小设为1天
#对一些ttl值低的大网站有用(低ttl用于负载均衡)
min_ttl=1d;
pdnsd默认的DNS服务器是OpenDNS(208.67.222.222/208.67.220.220),而据说用OpenDNS访问google有时候会出现反应慢的问题,所以建议直接换成google的DNS服务器:8.8.8.8和8.8.4.4。
接着,修改你的/etc/resolve.conf(或resolve.conf.head),将已有的nameserver信息清空,只留下面这一行:
nameserver 127.0.0.1
为防止resolve.conf被其他程序意外修改,可以加上sticky属性:
chattr +i /etc/resolve.conf
三、测试
启动pdnsd服务,然后测试一下可用性:
systemctl start pdnsd
nslookup www.google.com 127.0.0.1
如果正常返回,则说明pdns配置成功。现在可以将pdnsd设为开机启动项了:
systemctl enable pdnsd
至此,一个本机的DNS服务器搭建完成。
注意本文只解决了DNS查询速度问题,并不能解决DNS污染等问题。DNS污染可以通过专门的软件或将本地DNS配置成以TCP方式从远端DNS服务器取得查询结果,然后以UDP方式响应本机的查询请求的方式解决。pdnsd有一个专门的配置项目:
query_method=tcp_only;
-------------------------


pdnsd + opendns-dnscrypt 解决 DNS spoofing
描述:
    本机 192.168.0.65,局域网内有一台空闲 Linux 主机 192.168.0.223(Ubuntu 11.04)。现在希望在 192.168.0.223 上搭建一个靠谱的、可抗 DNS spoofing 的 DNS Server,作为本机 192.168.0.65 的 DNS 服务器。
下面是步骤。
一、安装 dnscrypt 并启动
首先下载 opendns-dnscrypt 的安装包并解压、安装:
    wget http://cloud.github.com/downloads/opendns/dnscrypt-proxy/dnscrypt-proxy-0.9.3.tar.gz
    tar zxvf dnscrypt-proxy-0.9.3.tar.gz
    cd dnscrypt-proxy-0.9.3
    ./configure && make –j2
    sudo make install
因为我们希望 192.168.0.223 作为 DNS Server 对外提供 DNS 服务,所以:(1)要安装 pdnsd(see 下一节);(2)要将 dnscrypt 开在别的端口(!= 53)上,以作为 pdnsd 的 server:
    sudo dnscrypt-proxy –local-port=50 –daemonize
请注意,local-port 和 daemonize 前是两个连接符(-)。
二、安装 pdnsd 并设置
    sudo apt-get install pdnsd
编辑其配置文件 /etc/pdnsd.conf,改动两个地方:
(1)设置 pdnsd 的 NS Server 为 dnscrypt:
(2)使得 pdnsd 可以为其他机器提供服务:
三、启动 pdnsd,测试
使得 pdnsd 作为 daemon 启动:
    sudo vim /etc/default/pdnsd
修改 START_DAEMON 的值为 yes。
启动 pdnsd:
    sudo /etc/init.d/pdnsd start
大功告成。将工作机的 DNS 设置为 192.168.0.223,并测试:
完工。 
------------------

用Pdnsd快速打造无污染高速缓存DNS服务器
前面讲Dnsmasq,我还打算下一篇写Dnsmasq for Ubuntu/DD-WRT来搭建家庭DNS缓存服务器呢,没想到这么快我就“变心”了Orz…其实从Dnsmasq转变到Pdnsd的原因很简单,一是Pdnsd原生支持TCP形式来访问DNS服务器,我就不需要在跑Tcp-DNS-proxy了;二是Pdnsd也能通过变通的方式来让特定的域名来走特定的DNS服务器;三是Pdnsd可以自定义TTL时间,也就是可以自己定义缓存保存的时间;四是不知道是我机器还是系统的问题,Dnsmasq在我的机器上跑起来老是各种抽风Orz…
Pdnsd在MacOS X上安装还是蛮简单的,只需要brew install pdnsd即刻自动安装了。brew这个命令是homebrew这个软件包的命令,至于homebrew以前已经讲过很多很多次了,这里就不在罗嗦了。
安装完成之后我们需要配置一下Pdnsd,它的配置文件默认是在/usr/local/etc/pdnsd.conf.sample(如果你是用homebrew安装的话),这是一个默认的配置文件模板,我建议拷贝一个或者新建一个配置文件,而不动这个默认的配置文件模板。因为如果将来有配置参数错误,或者配置文件写坏了,我们还可以有这个模板来参考或恢复。
你可以用cp pdnsd.conf.sample pdnsd.conf命令来从配置文件模板拷贝出来一个配置文件,然后在其中修改。但是由于这个模板文件里废话太多,可读性不好,我一般都是新建一个配置文件来写入自己所需要的功能配置,使用touch pdnsd.conf命令来创建一个空白的配置文件。
下面是我的pdnsd.conf配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
global {
        perm_cache=4096;
        cache_dir="/usr/local/var/cache/pdnsd";
        max_ttl=604800;
      query_method=tcp_only;
        paranoid=on;
        server_port=53;
        server_ip="127.0.0.1";
      min_ttl=1d;
      max_ttl=1w;     
}

server {
        label=GoogleDNS;
        ip=8.8.8.8, 8.8.4.4;
        timeout=30;
        interval=30;
        uptest=ping;
        ping_timeout=50;
      purge_cache=off;
}

你可以将它复制到你的配置文件中直接使用,其中只需要注意的是perm_cache这个参数代表了你要缓存多少DNS信息,min_ttl这个参数代表了缓存的DNS信息的最短有效期,max_tll这个参数定义了缓存的DNS信息最长的有效期,一般min_ttl的时间最好大于max_ttl,我定义的min_ttl1d,也就是1一天。
另外一个比较重要的参数是query_method,我写的参数是tcp_only,也就是强制只使用TCP方式去查询DNS服务器,这个参数一定要是TCP方式,否则还是会遭到DNS污染,一切都白费了。最后的server,就是你指定的DNS查询服务器,这里使用的是Google的DNS,当然你也可以用OpenDNS,只要你乐意。
另外Pdnsd还可以通过配置让指定的域名来走指定的DNS服务器来进行解析,比如用GoogleDNS来解析国外服务器很方便,但是解析国内服务器的话就会绕远路。所以我们要对Pdnsd进行配置,让它更加科学的来解析DNS,让我们访问国内的网站不至于太慢。
通过查看配置文件模板就可以很容易的看明白,Pdnsd是通过exclude的方式来排除域名的。比如在label=GoogleDNS参数下面新建一行exclude=.cn,.youku.com;,这样Pdnsd就会在GoogleDNS设置里排除末尾带.cn的域名和youku.com域名。在你解析它们的时候,Pdnsd会交给下面的域名服务器组来解析,我用以下配置文件来示例一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
        label=GoogleDNS;
        ip=8.8.8.8, 8.8.4.4;
        timeout=30;
        interval=30;
        uptest=ping;
        ping_timeout=50;
      purge_cache=off;
      exclude=.cn,
      .youku.com,
      .taobao.com;
}

server {
  label=ChinaDNS
  ip=202.102.152.3, 202.102.154.3;
}

Pdnsd来读配置文件的机制是上面的配置的优先级总是高于下面的配置的优先级,也就是说写在最上面的DNS解析服务器配置模块的优先级要高于写在下面的,是一个层级结构。而上面的配置文件在最上面的解析服务器模块里定义了排除.cn后缀和youku.com,taobao.com,这个几个域名。这样Pdnsd就不会使用GoogleDNS这个解析配置模块来解析.cn后缀和youku.com,taobao.com域名,而转交给下一个域名解析模块来解析,也就是转交给ChinaDNS来解析。
如此我们就可以将经常访问的国内网站写入GoogleDNS模块里的exclude参数后面来进行排除,然后在用国内的DNS服务器来解析,来优化网络。我用这种方式是因为我上的国内网站屈指可数,没有几个,而如果你上国内网站很多,上国外网站就几个的话你也可以反过来写,以免花太多的精力来写这个配置文件,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
server {
      label=ChinaDNS
      ip=202.102.152.3, 202.102.154.3;
      exclude=.twitter.com,
      .youtube.com,
      .google.com,
      .facebook.com;
  }
  
server {
  label=GoogleDNS
  ip=8.8.8.8, 8.8.4.4;
}

这样就会把上面写的这些不存在的网站(你懂的)的域名排除,不用国内的DNS来解析,而转交给GoogleDNS来解析了。
最后我们还需要给Pdnsd的缓存文件夹赋予一下权限,也就是上面配置文件里写的/usr/local/var/cache/pdnsd目录,当然你也可以根据你的喜好来指定其他目录。我比较懒,直接用root权限来运行Pdnsd,所以我chown root:admin /usr/local/var/cache/pdnsd,如果你用别的账户,请自行授权,或者777也行。
以上配置都完成之后,你就可以启动Pdnsd来进行测试了,用命令sudo pdnsd来启动它,然后将你的系统的DNS服务器修改为127.0.0.1,也就是本机。现在你就可以上网进行测试了,如果测试都没问题,都是按照你所想的规则来进行解析的话,下面我就需要开始新建一个启动文件,来让MacOS X开机自己自启动Pdnsd。
touch /Library/LaunchDaemons/pdnsd.plist
然后写入以下:

pdnsd.plist 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
      <key>Label</key>
      <string>pdnsd</string>
      <key>Program</key>
      <string>/usr/local/sbin/pdnsd</string>
      <key>RunAtLoad</key>
      <true/>
      <key>ServiceDescription</key>
      <string>pdnsd dns caching daemon</string>
  </dict>
</plist>

其中唯一需要注意的就是/usr/local/sbin/pdnsd,这是Pdnsd可执行程序存在的目录,如果你也跟我一样是通过homebrew安装的,那就不需要修改了,否则你可以通过which pdnsd命令来查看Pdnsd可执行程序的目录。
现在你就可以重启计算机了,如果一切正常Pdnsd就会在开机时自动启动了,你可以通过sudo ps aux | grep dns名来来看Pdnsd是否已经启动。
PS之前的pdnsd.conf设置有一些配置问题,可能会造成抽风,以下是又经过修改的版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
global {
        perm_cache=4096;
        cache_dir="/usr/local/var/cache/pdnsd";
        status_ctl = on;
      query_method=tcp_only;
        server_port=53;
        server_ip="127.0.0.1";
      min_ttl=1d;
      max_ttl=2d;   
      timeout=10;  
      neg_domain_pol=on;
#       paranoid=on; 
}

server {
        label=GoogleDNS;
        ip=8.8.8.8, 8.8.4.4;
        timeout=4;
        interval=10m;
        uptest=ping;
        ping_timeout=50;
      purge_cache=off;
  }
  
source {
  owner=localhost;
  file="/etc/hosts";
}
 
 
rr {
  name=localhost;
  reverse=on;
  a=127.0.0.1;
  owner=localhost;
  soa=localhost,root.localhost,42,86400,900,86400,86400;}
related post: