Total Pageviews

Wednesday, 12 December 2012

使用国外 DNS 造成国内网站访问慢的解决方法


你是否是一个使用国外 DNS 的中国网民?你是否发现使用国外 DNS 之后访问某些国内网站奇慢无比?这不是 DNS 慢,而是电信到联通的线路太慢。如果你愿意小小地折腾一下,那么跟随本文,你可以解决这一问题。

一、为什么要用国外的DNS

由于众所周知的问题,国内 DNS 服务器解析国外网站会遭到 DNS 污染和投毒,使之解析到完全虚构的 IP 上,造成「开了 VPN 也没法访问 Twitter 或 Facebook」等问题。以下是一个例子:
wzyboy@vermilion:~$ dig twitter.com @8.8.8.8 +short
199.59.148.82
199.59.149.230
199.59.148.10
wzyboy@vermilion:~$ dig twitter.com @221.228.255.1 +short
93.46.8.89
Twitter 正确的 IP 地址应该是 199.59.148.0/24 里的那几个,但是如果用 221.228.255.1 这台中国电信的 DNS 服务器查询,查到的就是不知道什么鬼地址了,地理信息是在意大利,乱七八糟的。正是因为这样的 DNS 解析不正确的情况出现,不少人转而使用了国外的 DNS 服务器,如老牌的 OpenDNS 以及这几年新崛起的好记又好用的 Google Pulic DNS 即 8.8.8.8 和 8.8.4.4。使用它们进行查询,再配合以 VPN 或者浏览器的远程 DNS 解析,便可避免 DNS 污染的情况出现,从而解析出正确的地址。
此外,拒绝使用电信的 DNS 服务器,还可以避免烦人的「114 上网导航」页面……

二、为什么使用国外 DNS 会「慢」

我是在「慢」上加了引号的,因为这其实不是国外 DNS 慢,而是你要访问的网站的 CDN 分配错误,慢。由于国内各大运营商之间的主干线路带宽太窄,所以导致「最远的距离是从电信到联 通」,电信用户访问联通的服务器非常慢,联通用户访问电信的服务器也非常慢,相信这都是大家有体验的。因此,国内不少网站都用了双线 CDN,在电信的机房里放点服务器,再在联通的机房里放点服务器。运用智能 DNS 技术,当你访问网站的时候,DNS 根据你的来源 IP 判断你是电信用户还是联通用户,然后再返回相应的 IP 地址,这样你会访问到就近的、同运营商的服务器,访问速度就大大提升了。而如果使用国外的 DNS 的话,你的查询来源来自国外,国内网站的 DNS 无法判断你是电信用户还是联通用户,就胡乱分配你一个服务器。比如我是一个江苏电信的用户,但当我访问淘宝网的时候,淘宝的 DNS 把我解析到青岛联通的服务器上,奇慢无比。所以:
很多人认为 Google Public DNS, OpenDNS 等「慢」,主要不是查询慢,而是电信到联通之间太慢。
当然了,如果硬要比较查询的话,倒也是会慢很少一点的:
;; 使用 8.8.8.8 解析 www.google.com 耗时 79 毫秒
;; Query time: 79 msec
;; SERVER: 8.8.8.8#53(8.8.8.8)
;; WHEN: Thu Sep 6 17:20:37 2012
;; MSG SIZE rcvd: 143
;; 使用中国电信 221.228.255.1 服务器解析 www.google.com 耗时 6 毫秒
;; Query time: 6 msec
;; SERVER: 221.228.255.1#53(221.228.255.1)
;; WHEN: Thu Sep 6 17:20:44 2012
;; MSG SIZE rcvd: 284
别看 6 毫秒和 79 毫秒差别很大的样子,但是人类是很难感觉出来的,而且,这只是查询时间,与实际的访问速度无关,就算你一整天都在刷 www.google.com,也就每小时慢个几百毫秒的样子,根本感觉不出来。真正慢的原因,还是上文所说的「电信到联通」的问题。

三、问题的解决思路

现在问题明确了:使用国外 DNS 之后,查询来源变成国外的 IP,使用了 CDN 加速的国内网站的 DNS 会无法判断你的来源,胡乱给你分配一个地址,如果不是同一个运营商的,访问速度便会很慢。
那解决方案也就出现了:让国内网站的 DNS 服务器知晓你的来源,从而给你分配正确的服务器 IP。于是 Google 起草了一个专有协议,叫 EDNS,在 DNS 查询请求中包含源地址,这样淘宝就知道查询来源不是 Google 服务器,而是电信的某用户,就不会把你扔到联通服务器上了 。听起来很美好是吧?不过这个协议不开放,目前几乎没有人用,所以,问题丝毫没有解决。
新思路是:访问那些会因 CDN 加速解析错误而极其缓慢国内网站的时候,直接向国内的服务器发送请求,让 DNS 知晓你的来源,给你分配个正确的 IP。访问其他网站的时候,再通过国外的 DNS 查询。
听起来很简单的样子,实现起来也不难:用 dnsmasq 在本地搭个 DNS 缓存服务器,规定哪些域名用哪个服务器查就好了。

四、安装及配置 dnsmasq

安装 dnsmasq

dnsmasq 是一个非常轻量的 DNS 缓存及 DHCP 服务器,在我的 Arch Linux 上只占用了 368 KiB 的磁盘空间,相比功能极其强大的 BIND9 来说小多了(BIND9 的安装体积是 6.23 MiB)。不光是体积小,它的功能也很专一,配置起来也是十分方便的,五分钟就可以搞定。
Ubuntu 12.04 及之后的版本应该自带了 dnsmasq。如果没有,可以使用 sudo apt-get install dnsmasq 安装。Arch Linux 直接sudo pacman -S dnsmasq 即可。我的笔记本电脑需要给手机 DHCP 及 IP 转发用,因此早就安装了 dnsmasq,但是直到今天才想起这么用它……

配置 dnsmasq

dnsmasq 的各参数可以通过 man dnsmasq 查看,配置文件中也有许多清晰明了的注释。默认的配置文件位于/etc/dnsmasq.conf,打开它,可以更改这几个地方:
no-resolv
no-poll
server=8.8.8.8
server=8.8.4.4
server=/cn/114.114.114.114
server=/taobao.com/114.114.114.114
server=/taobaocdn.com/114.114.114.114
server=/tbcache.com/114.114.114.114
server=/tdimg.com/114.114.114.114
第一行的 no-resolv 和第二行的 no-pull 让 dnsmasq 不要通过 /etc/resolv.conf 确定上游服务器,也不要检测/etc/resolv.conf 的 变化(因为我们就是要拿本机当服务器嘛),接下来两行指定 dnsmasq 默认查询的上游服务器,此处以 Google Public DNS 为例,喜欢用 OpenDNS 的也可以改 OpenDNS。接下来就是规定一张名单了,把一些国内网站的域名写在这里即可。比如 server=/cn/114.114.114.114 便是把所有 .cn 的域名全部通过 114.114.114.114 这台国内 DNS 服务器来解析,你也可以改成其他的国内 DNS 比如你的运营商提供的 DNS。接下来四行是淘宝的几个域名,让它们也通过国内的 DNS 服务器解析。
这样分流操作之后,默认所有域名都通过 8.8.8.8 和 8.8.4.4 解析,但是所有的 .cn 域名以及淘宝的域名通过 114.114.114.114 这台国内 DNS 服务器解析。当然,除了淘宝网,你也可以添加更多的域名,根据自己的喜好,把经常访问,但是使用国外服务器解析到很慢的服务器上的网站域名都可以添加进 去,不过:如果这个网站本身就只能一台服务器,没有 CDN 加速,那再怎么添加也是无济于事的,得让网站管理员去买双线机房……另外,在写这篇文章的时候,发现 @felixonmars 维护了一张国内常用的、 但是通过国外 DNS 会解析错误的网站域名的列表,据他所说,这是他在公司里部署这一套东西之后,公司里其他人报怨「慢」的网站域名收集来的,应该囊括了绝大多数有此问题的网 站,值得依赖,欢迎选用。如果觉得直接把这么多域名加在 /etc/dnsmasq.conf 里不爽的话,可以在dnsmasq.conf 里把 conf-dir=/etc/dnsmasq.d 这一行取消注释,然后把在 /etc/dnsmasq.d 里弄点列表。比如我就是把@felixonmars 维护的列表放在 /etc/dnsmasq.d/china.conf 里。
配置好之后,保存,Ubuntu 可用 sudo service dnsmasq restart,Arch Linux 可用 sudo rc.d restart dnsmasq 重启 dnsmasq。如果没有错误的话,这时本地的 dnsmasq 已经跑起来了。

测试 dnsmasq

测试一下:
wzyboy@vermilion:~$ dig www.taobao.com @8.8.8.8 +short
www.gslb.taobao.com.danuoyi.tbcache.com.
scorpio.danuoyi.tbcache.com.
119.167.195.251 → 这是淘宝的青岛联通的服务器,我用江苏电信连奇慢无比
119.167.195.241 → 这也是青岛联通
wzyboy@vermilion:~$ dig www.taobao.com @127.0.0.1 +short
www.gslb.taobao.com.danuoyi.tbcache.com.
scorpio.danuoyi.tbcache.com.
222.186.49.251 → 解析到常州电信了,快!
61.155.221.241 → 这是上海电信
wzyboy@vermilion:~$ dig twitter.com @127.0.0.1 +short
199.59.150.7 → Twitter 还是用 8.8.8.8 解析的,所以解析出来是未经污染的正确地址
199.59.148.82
199.59.149.230
效果很明显,这时可以把本地的 DNS 设为 127.0.0.1 了。大部分 Linux 用户直接更改 /etc/resolv.conf 的内容为
nameserver 127.0.0.1
即可。Ubuntu 12.04 及以后的用户,可能需要对 resolv.conf 做一些手脚,具体参考这里。如果不愿意改的话,可能每次联网都要手工改一次 resolv.conf,或者在 NetworkManager 中手工指定 127.0.0.1 为 DNS。DHCP 用户的话,可以通过/etc/resolv.conf.head 之类的文件来保证 127.0.0.1 在第一行。
这样配置完之后,如果你没有在 dnsmasq 里限定查询 IP,那么你的家人、朋友们也是可以把你的电脑作为 DNS 服务器的。如果你本地是 VPN 全局翻墙的话,需要把你选择的国内 DNS 服务器通过路由表加入直连的范围内。当然,已经使用 chnroutes 的就不需要了。

五、我不是 Linux 用户怎么办?

如果你是 Windows 用户

参考这个问题,去配个 BIND9 的 Windows 版本试试吧。或者可以装个 dnsmasq 的 Windows 代替品。

如果你是 Mac OS X 用户

Mac OS X 的 resolver 比较独特,似乎有比较简陋的解决方法,参考这篇文章。另外,OS X 似乎也是自带 named 的,所以……
另外,安装 Homebrew 吧,然后 brew install dnsmasq 喽……

其实还有更通用的方法

听说过 VirtualBox 吗?开源、免费、强大的虚拟机软件。可以装个最配置非常低下的虚拟机,比如 32 MiB 内存甚至 16 MiB 内存的虚拟机(要知道 64M 内存的 Linux 已经可以跑 WordPress 这庞然大物了),装个最简单的小 Linux,比如只有 37M 的 Ubuntu Core,然后装上依赖包几乎没有的 dnsmasq,再把 Windows / OS X 的 DNS 设为虚拟机的 IP 地址,于是便可以用了。在当今内存动辄 4 GiB 的情况下,拿 16MiB 内存出来换个更舒畅的上网体验,还是很不错的。

六、尾声

祝各位读者折腾成功,上网愉悦。
补充:其实这样本地 DNS 缓存服务器,还有这样的好处:
wzyboy@vermilion:~$ dig urdomain.com

; < <>> DiG 9.9.1-P2 < <>> urdomain.com
;; global options: +cmd
;urdomain.com.   IN A
urdomain.com.  103 IN A 198.244.51.13
;; Query time: 307 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Sep  6 21:32:07 2012
;; MSG SIZE  rcvd: 54

wzyboy@vermilion:~$ dig urdomain.com
; < <>> DiG 9.9.1-P2 < <>> urdomain.com
;; global options: +cmd
;urdomain.com.   IN A
urdomain.com.  95 IN A 198.244.51.13
;; Query time: 2 msec
;; SERVER: 127.0.0.1#53(127.0.0.1)
;; WHEN: Thu Sep  6 21:32:15 2012
;; MSG SIZE  rcvd: 43
看出来了吧?

from https://wzyboy.im/post/874.html
-----------------

Windows 下使用国外 DNS 访问国内网站慢的解决方法

标题好像有点绕口,其实就是因为要科学上网而用国外 DNS,例如 OpenDNS 、Google 的 8888,8844,而国内有两个同行近在眼前却隔扇厚墙:联通和电信,而国内很多网站都是多线路自动分配联通还是电信的服务器IP给你,问题就是使用国外 DNS 无法判断……
这就造成使用国外 DNS 有时会出现你是电信用户扔给你联通服务器 IP,具体不说,会用国外 DNS 的朋友都懂的。这里主要说说解决办法。
我是 Windows 重度中毒者,所以需要在 Windows 下的软件,搜来搜去找到的是 Dual DHCP DNS Server,因为没有中文版,也就没有中文说明,而且随便搜一下竟然没有一篇文章写如何设置……囧,只好自己摸索一下了。

Dual DHCP DNS Server

What are DHCP and DNS servers
DHCP Server alots the IP addresses to computers, while DNS server resolves them.
You need DHCP Server if you do not want to manually maintain IP Addresses or
you have less IP Addresses than number of machines you have, as dynamic DHCP Server will
recycle IP Addresses on machines.
DNS Server is needed for resolving hostnames to their IP addresses. Normally your
ISP will provide you with DNS Service. You may have your own DNS Server, which will
resolve hostnames by forwarding them to ISP's DNS Server and cache the addresses also.
这软件支持 DHCP 和 DNS 服务的,我只要 DNS,下面是一些简单的设置说明,具体我也懒得去深入了解,反正只要解决我文章标题的问题就行了。(下面的说明都是假定你的电脑通过路由器上网,拨号的类似自行修改)
  1. 下载安装好(假定在 D:\DualServer)
  2. 进入 D:\DualServer 目录,用文本编辑器打开 DualServer.ini
  3. 找到 [SERVICES] 项部分,默认是开启 DHCP 和 DNS 服务的,因为我只要 DNS 功能,所以只开启 DNS 功能只要去掉 ;DNS 前面的英文分号 ;
  4. 继续找到 [FORWARDING_SERVERS] 项,这里是指定默认的 DNS 服务器,这里我用 Google 的,所以加上
    8.8.8.8
    8.8.4.4
  5. 然后就是重点了,找到 [CHILD_ZONES](注:6.95RC后改名为[CONDITIONAL_FORWARDERS]),这里是针对关键字自定义 DNS 服务器的地方,下面说说格式
    - 拿淘宝网站来说明吧,淘宝一般的域名有:taobaocdn.com、taobao.com、tbcache.com、tdimg.com
    . 我们要设置这几个域名走电信的 DNS(这里我用路由器DNS代理地址——即路由器本身IP),那么格式如下
    taobaocdn.com=192.168.1.1
    taobao.com=192.168.1.1
    tbcache.com=192.168.1.1
    tdimg.com=192.168.1.1
    . 如果有多个 DNS 就这样(例如广东这边电信的 DNS 一般是 202.96.134.133 和 202.96.128.166)
    taobaocdn.com=202.96.134.133,202.96.128.166
    2013.02.20 Update:Guo.Andy 在评论里提醒新版 V6.95RC 改了设置名(点击这里),我还没验证,用新版的朋友注意一下。
  6. 查看自己网卡的 IP 地址,因为 DualServer 默认会获取网卡的 IP 地址作为本地 DNS 服务器地址,不知道的可以在命令窗口敲 ipconfig 得到,这里假定是 192.168.1.100
  7. 修改连接路由器的那个网卡的 DNS 服务器地址为 192.168.1.100(自淫?网卡自己的IP……)
  8. 运行 RunStandAlone.bat,运行后会出现命令窗口显示 log,这样就OK了
PS1:如果你不想每次都要运行 RunStandAlone.bat 和看到那碍眼的命令窗口,那么你可以注册为系统服务,只要运行 DualServer.exe,然后去系统服务(命令行敲 services.msc)那里启动此服务,以后就会自动运行了,不过注意,如果你修改了 DualServer.ini 参数,需要停止再启动此服务——嫌麻烦就重新启动计算机
PS2:@felixonmars 这喵的维护了一张国内常用的、但是通过国外 DNS 会解析错误的网站域名的列表,“Auto DNS Configuration For Websites Located in China”里面的就是,不过 要改下格式,例如:
server=/115.com/114.114.114.114
改为
115.com=114.114.114.114
添加进前面说的 DualServer.ini 的 [CHILD_ZONES] 下面(可以copy列表到文本编辑器批量修改)
折腾完,祝大家科学上网愉快.
from http://zww.me/archives/25714/
---------------
mac的诡异 DNS 问题

用 Mac 一年来遇到最诡异的问题,就是 Snow leopard 的 DNS 问题了,最常遇到的状况是,dig/nslookup/host 都能够正确解析域名,但 ping 却不能解析任何域名,其他的一票软件如 ssh、浏览器等也因为解析不了域名而不能正常工作。
发生这种状况时,我一般会看看 mDNSResponder 是否异常,曾多次遇到 mDNSResponder CPU 占用 100%,这种情况下 kill 掉 mDNSResponder,等它自动重启之后,DNS 解析问题通常就会恢复正常。但也不尽如此,我越来越多次有类似的 DNS 解析问题时,重启 mDNSResponder 进程并不凑效,log 中也未能发现对我有意义的线索。
今天又遇到了这样的问题,与以前一样,dig/nslookup/host 能够正确解析所有域名,ping 和其他软件则不能,和之前略有不同的是,这次的状况是 VPN 内网的域名不能解析,而其他的外网域名可以正常解析,于是花了点时间做了些探索,同时也找到了一篇详尽解释Snow leopard DNS解析问题的文章
简单说来,dig/nslookup/host 对 /etc/resolv.conf 中的 DNS server 直接进行查询,因此只要 DNS server 本身工作正常,这三个程序都可以正常解析。而系统的其他部分则不同,在 Mac OS X 10.6 Snow leopard 中,由 mDNSResponder 负责所有的 DNS 解析,包括单播 DNS(传统的域名解析)和多播 DNS(Bonjour),mDNSResponder 并不使用 /etc/resolv.conf 中的 DNS,实际使用的 DNS 是使用 scutil 来设置的,并可以使用 scutil –dns 来查看当前使用的 DNS server 和顺序,而在 resolv.conf 中看到的 DNS,只是 mDNSResponder 列出来的 primary DNS resolvers。
以 xxx.douban.com 这个子域为例,假设内部 DNS 地址为 1.2.3.4,对于我遇到的内部域名不能正确解析的情况,可以使用 resolver(man 5 resolver) 来解决,方法是:

1
2
sudo mkdir -p /etc/resolver
echo "nameserver 1.2.3.4" > /etc/resolver/xxx.douban.com

意指使用 1.2.3.4 作为 xxx.douban.com 这个域的域名服务器。
resolver 的这个功能同时也给我带来了极大的便利,我以前指定用特定的服务器来解析某域时,通常是在本地跑一个 dnscache 实例,在 dnscache 中做类似配置,现在直接使用 resolver 即可,比如我可以在 openvpn 服务器端推送到 8.8.8.8 的路由记录,使得到 8.8.8.8 的链路经由 VPN 加密,然后在本地配置指定比如 twitter.com 使用 8.8.8.8 来解析,就可以解决国内劫持 twitter.com 域名的问题了.





我目前的做法与这个方法类似,在本地起了一个DNS,把内部的域名本地forward到公司的内网DNS上来。其余的都由本地的dns做反复查询,本地默认路由是openvpn,再添加国内网段的静态路由,这样的好处是基于DNS的CDN系统同样管用,国外的主机都走了openvpn,国内都走了办公网出口。



也是个好方法,不过这样的话本地需要添加N多条静态路由吧?求分享国内网段。我现在的做法是,openvpn不push默认路由,而是只push到特定主机的路由,比如DNS和某些需要不使用代理直接访问的主机,而本地应用访问国外主机时都使用开在openvpn服务器上的socks代理(nylon),由浏览器的proxy插件来维护需要使用代理的域名列表。DNS的做法和你的一样.



@Xupeng
对,要添加很多的路由。路由表从这里来的-http://code.google.com/p/chnroutes/

from http://blog.xupeng.me/2010/10/25/weird-snow-leopard-dns-issue/