给域名解析添加备份

5月19日,国内的免费智能域名解析服务商 DNSPod 遭到大规模的恶意攻击,意外中断服务若干小时。我的博客域名当时也托管在 DNSPod 处,被攻击的时候无法解析域名,幸好自己记得虚拟主机的 IP 地址。当时只好自己在系统中编辑 hosts 文件来手动完成解析服务。

意外发生以后,再考虑到 DNSPod 之前数次被攻击的历史,我决定把域名转移到其它的服务商,更重要的,是给域名添加备份解析服务器。

DNS 作为互联网基础设施,其稳定性是很值得关注的。传统的做法是域名解析服务商(无论是免费解析还是域名注册商提供的解析)提供至少两台服务器用作域名解析服务。比如 DNSPod 就有六台服务器用作免费解析,EveryDNS 有四台服务器。这种设计是为了提高冗余度以增加域名系统的稳定性。对于意外的服务器当机、网络出现故障等问题,这样做是比较保险的。DNSPod 偶尔就有某台服务器要停机维护的情况,但这并不会给正常解析带来什么麻烦,因为有其它的五台服务器正常工作。可是对于恶意攻击,多台服务器的冗余就没有意义了。攻击者在能力足够的情况下(直白的说就是肉机足够多),完全可以利用大流量把所有的服务器同时攻击一遍。而且大部分时候他们都会这么做,要不然只攻击一部分其实没有效果。DNSPod 就这样被大流量攻击打倒,无数的域名便受到牵连。

在台湾网友的博客上看到《如何用xname搭配zoneedit做备援DNS》这篇文章,于是照着做了一下,把自己的域名解析转移到了 ZoneEditEveryDNS。设置上都是大同小异的,简单说一下。

  1. 注册 ZoneEdit 和 EveryDNS 账号,并登录。
  2. 在 ZoneEdit 中添加自己的域名,比如我的就是 xiaoding.org ,然后添加自己的解析记录,包括 A 记录(IP地址)、CNAME 记录(别名)、MX 记录(邮件服务)等等。Nameserver 这个地方,ZoneEdit 会给出自己的两台服务器地址,稍微记一下数字较小的那个服务器的地址。
  3. 域名解析记录添加完之后,选择 ZoneEdit 的 Advanced 页面,打开最下面的“Edit Security Settings”,然后在“Restrict zone transfers to these IP’s”这个编辑框中填入“0.0.0.0/1;128.0.0.0/1;”(不含此处的引号)。注意这个填法将允许所有的区域传送请求,直白的说就是你的域名记录将对所有人公开。这么做是为了方便,因为 EveryDNS 或者 XName 对于他们的区域传送服务器的 IP 说法十分不清楚,而且时间长了也有可能变动。只好图个方便在这里允许所有的人来抓取 DNS 记录。相信一般人在这里也不会藏什么秘密。 😛
  4. 来到 EveryDNS 的设置页面。左边是添加记录的地方,basic 框中填入你的域名,比如 xiaoding.org ,选中下面的“Make domain secondary using”,然后输入刚才 ZoneEdit 的那个服务器的地址,点击“Advanced”按钮,添加就完成了。
  5. 在 ZoneEdit 的 Nameserver 选项中,把 EveryDNS 的四台服务器地址添加进去。分别是 ns1.everydns.net ns2.everydns.net ns3.everydns.net ns4.everydns.net
  6. 设置到此结束。EveryDNS 的服务器会自动地向 ZoneEdit 的 Master nameserver 同步。等几个小时以后可以查询自己的 DNS 记录以便确认是否同步成功。

使用如下命令查询 DNS 的 SOA 记录:

nslookup -q=soa xiaoding.org ns3.zoneedit.com

查询结果示例:

xiaoding.org
        primary name server = ns3.zoneedit.com
        responsible mail addr = soacontact.zoneedit.com
        serial  = 1242714018
        refresh = 14400 (4 hours)
        retry   = 7200 (2 hours)
        expire  = 950400 (11 days)
        default TTL = 3600 (1 hour)

注意把 xiaoding.org 换成自己的域名, ns3.zoneedit.com 换成自己的域名解析服务器(每个人可能不同)。针对每个服务器都查询一次,在返回的 SOA 记录中比较一下记录的序列号是否相同,如果相同即表明备份 DNS 设置成功。这样无论 ZoneEdit 或者 EveryDNS 哪一家有问题,自己受的影响都会小很多。

DNSPod 遭受攻击,博客域名再次转移

国内著名的免费 DNS 解析服务商 DNSPod 在今天凌晨再次遭到攻击。攻击手法是 DDoS,以极高的流量冲击域名服务器和机房网络,使之无法正常提供服务。

我凌晨熬夜的时候试图打开自己的博客,但地址解析失败导致无法打开。今天下午再度尝试,发现在教育网内尝试了几个服务器,还是无法解析我的域名。公网的解析现在应该已经恢复了,我用其它网站提供的DNS测试工具测试结果正常。

这次被攻击给域名托管在 DNSPod 的所有用户带来了极其不良的影响。DNS 域名系统作为互联网基础设施,在整个网络的运行中起到了重要的作用,所以 DNS 失效对于网站来说是灭顶之灾,因为网站与用户就这样生生地隔离开了。这次攻击连著名的 IT 资讯站点 cnBeta.COM 也被波及。从 whois 查询结果可以看到

Domain Name:cnbeta.com
Record last updated at 2009-05-12 05:37:27
Record created on 2003/6/22
Record expired on 2011/6/22

cnbeta 站点也在今天调整了自己的域名解析,以避开 DNSPod 被攻击带来的问题。

经历此事,再加上之前 DNSPod 各种原因遭到攻击的记录,综合考虑我还是决定把域名解析从 DNSPod 那儿转移到国外的 ZoneEdit 和 EveryDNS 上。这么做并非觉得国外的服务就一定能够稳定,事实上 EveryDNS 也有过被大规模 DDoS 攻击的历史。只是我决定了在域名上采用 Master/Slave 体系,由 ZoneEdit 充当 Master Server,EveryDNS 充当 Slave,这样我的域名解析就分布在六台不同地区的主机上,而且这六台主机分属两个不同的服务商。无疑这么做会大大提高域名的稳定性。

对于 DNSPod ,我还是心存感激并且大力支持的。毕竟 DNSPod 在中国这样险恶的环境中坚持着智能解析的免费服务,并且提供了“多线路智能解析”和“URL转发”这样的优秀功能,已经实属不易。这种外部攻击导致的服务故障算得上是意外情况,于情于理都应该宽容一些。至少不能像某些心安理得的人一样,稍有不顺意的地方开口就骂。

一直以来我都在找机会建议站长吴洪声提供 Zone Transfer 功能,这样就直接支持 DNS Backup 了,无论是 DNSPod 充当 Master 或者是 Slave ,共对于稳定性的提升都是有巨大帮助的。迫于网络环境的险恶,我选择了暂时搬到国外的两家免费解析服务。当然,在合适的时候,我会回来的。

WordPress 手动提速 – 缓存优化

由于大多数的 wordpress 博客都架设在与他人共享的虚拟主机上,所以速度和优化便成了 blogger 们经久不哀的话题。为了优化,我也看过不少的文章。看来看去,很多人只是老调重弹地讲了 WP Super Cache 插件;以及有些空泛地提出要去除不必要插件、优化 javascript 等,可惜这只说明了方向问题却没有点明该如何朝这个方向去做。只好依自己生平所学,手动地折腾了一把 WordPress 优化。

服务器端缓存机制

虚拟主机用户一般无法更改服务器的配置,我们也就不能在这方面有很大的期望。不过“缓存”这一手段仍然是一种相对可行的底层优化方法。Wordpress 有众多的缓存插件来支持这一行为,包括 WP Cache、WP Super Cache、DB Cache 等。

WP Cache 和 WP Super Cache 这样的插件通过生成 HTML 静态页面来降低服务器负荷,达到提速的目的。我个人却不太喜欢这样的方式。其原因有:一,这样做会丧失动态网站的灵活性。特别是那些根据客户端不同会作出不同响应的功能。比如我的主题中有一个 is_bot() 函数,用来针对搜索引擎的机器人作出一些 SEO 的调整。一旦我启用了静态缓存插件,便丧失了这种灵活性。有人说这些功能可以改成 Javascript 实现,但真要改动起来也比较麻烦,有些得不偿失。二,某些个人博客的瓶颈并不在PHP执行这个环节,而是客户与服务器之间的网络线路。甚至我认为,个人博客没有上万的 PV 完全没有必要采用静态化的策略。

DB Cache 插件我觉得可以试试,因为它的原理是缓存数据库查询,特别是虚拟主机中数据库服务器不是本机(localhost)时,这个插件会提高响应速度。但必须注意的一点是很多虚拟主机对于每用户可占用的内存是有限制的,如果这个值太低,那么这个插件也不太适用。

把缓存交给用户

与其在服务器上费力地设置缓存,更好的办法其实是“把缓存交给用户”。我用 Firebug + Yslow 分析自己博客的时候,发现它提示我的博客没有给静态内容设置缓存。于是用 cURL 连接到网站上通过观察 HTTP Header 来分析了缓存的机制。我的博客上 Apache 会发送“Last-modified”和“E-Tag” Header,这似乎也是大多数博客虚拟主机的配置。这样浏览器在请求的时候会发出“If-modified-since”请求,让服务器判断请求的内容(比如图片)是否在某个时间(通常是浏览器缓存的时间)以后发生变化。如果没有变化,服务器返回 HTTP 304 Not Modified 响应,浏览器则可以放心地使用本地缓存,从而降低了 HTTP 请求开销。

Yslow 建议给静态内容设置一个“永久”的缓存。这个永久通常是设置一年甚至更长的缓存期来实现的。设置缓存以后,服务器在对请求作出响应的时候会附加一个 Expires Header,告诉浏览器这个东西在多长时间内不会过期。这样浏览器就可以放心地使用缓存,甚至连 If-modified-since 请求和一个 HTTP 304 响应也不必要了。这样就大大地节省了在网络上的开销。访问者只是在第一次访问时会请求动态内容,接下来则会直接使用缓存的内容,达到了“把缓存交给用户”的目的。

实现方法

要做到这个也是件很容易的事情,对于 Apache 服务器来说,使用 mod_expire 就能轻松地设置缓存期。在 .htaccess 文件中加入以下内容:


# 启用缓存机制
ExpiresActive On

# 图片缓存时间为 1 年
ExpiresByType image/gif "now plus 1 year"
ExpiresByType image/jpeg "now plus 1 year"
ExpiresByType image/x-icon "now plus 1 year"
ExpiresByType image/png "now plus 1 year"

# Javascript, CSS 缓存时间为 12 小时
ExpiresByType text/css "now plus 12 hours"
ExpiresByType text/javascript "now plus 12 hours"
ExpiresByType application/javascript "now plus 12 hours"

有人要说,如果我的内容改变了怎么办呢?因为这样设置以后浏览器并不会向服务器询问是否有新的内容,而是老老实实地相信自己的缓存内容了。
如果你的改动是少数的几个图片,那么只需要在图片的 URL 后面自己加上一个任意的 query string 即可。比如说原来的图片 URL 是

http://blog.xiaoding.org/wordpress/wp-includes/images/smilies/icon_smile.gif

现在只需要在原地址后面加上一个 query 参数即可,此参数对于静态内容可以任意构造,我此处写的是 AnyQueryString

http://blog.xiaoding.org/wordpress/wp-includes/images/smilies/icon_smile.gif?AnyQueryString

这样浏览器会认为此时的图片与原来的不同,将再一次下载它。于是我们就达到了更新的目的。

WordPress 与 Qzone 和 Live Space 同步

背景及插件介绍

很多人倾心于 WordPress 博客平台的灵活性和可定制性,跑到 WordPress 中来写文章。但这样的话,文章一般只在由评论、Trackback/Pingback 等构成的博客圈内有影响,我们在 QQ、MSN 等即时通讯工具上的朋友就很难看到文章了(大多数人还不会用 RSS)。再者,QQ 和 MSN 对于自家的空间有良好的支持,如果有文章更新的话会有小星星或者小黄花的提示。这样我们如果将文章同步到 Qzone 及 Live Space 上,则可以达到一个推广的效果,可以利用之。

李光明同学写了一个 Post2qzone 插件,用来将 WordPress 中发布的文章同步到 Qzone 中。插件的原理比较容量理解。Qzone 和 Live Space 都支持邮件发布的功能。也就是说,可以通过发邮件到指定的邮箱来更新你的 Qzone 和 Live Space。但由于 Qzone 的邮件发布只接受从 QQ Mail 寄来的邮件,这就要求必须使用 QQ 邮箱的 SMTP 服务向 Qzone 的指定邮箱发信以同步更新 Qzone。 Live Space 的要求则宽松一些,可以自行设置发信的邮箱地址。

安装和设置

在安装前,首要先确认你的空间支持 socket 功能。没有此功能将无法使用 SMTP 服务来发送邮件,也就无法实现发布文章时同步更新。在 PHP 中调用 phpinfo() 函数,输出信息中有一个“Sockets support”,支持的话显示为 Enabled。

接下来是开通 QQ 空间、QQ 邮箱。登录到 QQ 邮箱,进入“设置”->“账户”,勾选“开启POP3/SMTP服务”,然后保存更改。这样就打开了 QQ 邮箱的 SMTP 功能。

然后下载 post2qzone.php,上传到 WordPress 插件目录,然后从插件面板启用此插件。在“设置”中有一个“Post2qzone”的页面。在此页面中设置你的 QQ 号、邮箱密码、邮件标题和邮件正文模板。

设置完成以后邮件同步发布应该就可以实现了。记得在 WordPress 中发布文章的时候,要在页面的“Post to qzone”选项中中勾选“Confirm publish”才会同步。临时不需要同步功能,可以去掉这个选项。

优化与提高

说了半天都是在说 Qzone 的事情,如何同时同步到 Live Space 呢?首先要在 Live Space 中启动邮件发布功能。登录到 Live Space,选择“选项”->“邮件发布”,在第一步中填入qq邮箱的地址;第二步中自己编造一个 secret word ,第四步中选择“立即发布”。然后直接用文本编辑器打开 post2qzone.php 插件文件,在 function Halo() 下面添加一行代码,就可以同时更新到 Live Space 上。

	function Halo($subject,$body){
		// BLOGNAME 替换为你的 Live Space 名称。比如网址 blogtest.spaces.live.com ,那么 BLOGNAME 就是 blogtest
		// SECRET 替换为 Live Space 设置中自己设定的单词,不要公开
		$this->AddAddress("BLOGNAME.SECRET@spaces.live.com","BLOGNAME.SECRET@spaces.live.com");
		$this->AddAddress("{$this->qq}@qzone.qq.com", "{$this->qq}@qzone.qq.com");
		$this->Subject = $subject;
		$this->Body	= $body;
		return $this->Send();
	}

添加好此代码以后,就可以同时通过邮件来更新 Qzone 和 LiveSpace 了。

由于此插件默认输出的是全文,为了增加自己博客的访问量,可以在插件中只输出摘要,同时给出原文链接。示意图如图所示。(此文为博客迁移后导入,图片已薨) 

怎么改我就不详细说了,无非是借用了 Advanced Excerpt 插件的处理思路来输出指定长度的摘要。我的 post2qzone 插件文章内容模板是这么写的,如下列出作为参考,摘要的效果可以在我的Live Space 上看到。

〖原文发表于<a href=”http://blog.xiaoding.org” target=”_blank”>我的部落格</a> http://blog.xiaoding.org 〗<br /><br />
{post_content}<br /><a href=”{post_link}”>阅读原文»</a> 

这儿是修改好的 post2qzone 插件的下载。(附件已遗失,不提供下载,可依文章思路自行修改)使用到了 mb_substr() 函数,不支持此函数的同学请自行依靠 Google 解决……

开源无线路由器固件上 Bug 的故事(二)

上一篇文章花了很大的气力讲了开放源代码第三方家用无线路由器固件的基本情况和绕过这个 bug 的办法。绕过 bug 在很多时候不失为一种有效的选择,特别是像之前我遇到的情况:开发组在一年内都没有对 bug report 作出任何响应。所以在失望之余也只好另辟奚径了,再用俗话说一遍就是“惹不起,躲得起”。 😉

下面把话说回来,毕竟文章的主题是 Bug 的故事,所以还是要接着往下说。只是后面的东西更偏向于技术,所以比较枯燥一点。

3. Bug 的认定和定位

这个 Bug 之所以让我记恨于心,的确是因为它太复杂了:从 bug 的发现认定,到 bug 定位和 bugfix,由于没有正式的官方支持,OpenSource Community 这种散兵游勇的开发全靠分散在各地的个人,每一步的进展都很艰难。

这个 Bug 造成的问题是目的MAC地址为 00-80-C2-00-00-03 的 802.1X 多播认证包被无线路由器丢弃(不会转发到 WAN 口),这样在路由器上运行的 Supplicant 程序在发出 logon request 之后便再也收不到回复。问题其实很明显,因为使用同一个程序,把网线插到 PC  上便能通过认证,显然就是路由器处理的问题。

那为什么说 bug 认定是一件麻烦事呢?因为后来才确定这个 bug 只存在于 Broadcom® 公司的 Roboswitch™ 系列交换芯片中。早期的 Linksys WRT54G 路由器使用的是 ADM6996L 交换芯片(ADMTek 已经被 Infineon 收购),在进行认证的时候是没有问题的。所以这个问题在此型号的机器上无法重现,再加上大家都从软件角度来思考(其实这是个硬件问题)。最后导致了两种声音:一种声音坚定地说自己遇到了 OpenWRT 的 bug,另一种声音说,这个 bug 在我的机器上无法重现,不能认定。这两种声音可以在 OpenWRT Trac 上的 Ticket 1862 看到。

 接下来有人发现“It has also worked for me on WRT54G 1.0-2.0. On WRT54G 4.0 it does not work.”,大家这才意识到这是 BCM5325 交换芯片搞的鬼。后来的 BCM5352 和 BCM5354 芯片内部都集成了一个交换模块,因此也理所当然地继承了这个 bug 。

修订:根据 jacky235 的消息,8230-4 和 WZR-G108 使用了 BCM5325A2KQM 交换芯片,但可以通过认证。而 OpenWRT Ticket 1862 上出现问题的是 BCM5325E 交换芯片,此芯片支持额外的管理功能和 802.1x EAPOL filtering 。所以将出问题的交换芯片定位到 BCM5325E 上面。集成了交换芯片的 BCM5352 和BCM5354 依然有问题,这个我自己可以证实。

此 Bug 的产生机理是什么呢?其实话说回来,这本来是 Braodcom 设计出来的 feature ,目的是为了使交换芯片的工作模式更加灵活一些,可是 Broadcom 的保守和封锁让这个 feature 在这里适得其反。(关于bug 和feature 的辩证关系,请看 atppp 的文章)如果芯片工作在 Default Mode ,那么会丢弃 802.1x 认证多播包 00-80-c2-00-00-03 ,如果芯片工作在 Frame-Management Mode ,则会把此包转发到 Frame Management Port 。如此简单的逻辑

4. Bugfix 和当前问题

这个 bug 的修复就更棘手了。人们总算搞清楚了问题的所在,但就是没办法去修复它。因为你无论是 Google、Yahoo 还是百度都找不到详细的 BCM5325 芯片资料。所有宣称有 Datasheet 的网站上下载回来的只有两页纸的 Product Brief。这东东在 Broadcom 自己的网站上就能下载到,无非就是花一页纸吹了一下自己这个芯片有如何如何的 feature 云云,然后再花了一页纸作 Overview,扔一个架构图上去完事儿,真是印证了 Brief 这个词。

后来我才从某个网页上无意得知,Broadcom 的 Datasheet 一般是不公开的。只在有渠道的代理商那儿有,只有从人家那儿拿货然后签订一个保密协议,人家才会给你一份 PDF 文档。当然给你的文档是没法传播的:每一页纸上面都斜贯着长长的一串水印——谁泄露出去了谁承担责任。Broadcom 这招的确狠,可也给 bugfix 工作设置了最大的屏障。

针对这个 bug 给出解决方案的是 Jouke Witteveen。他的解决方案没有去 patch OpenWRT,而是给 wpa_supplicant 上的 wired Driver 作出了修正。他提出了一个新的 roboswitch driver 专门用于 Roboswitch 上的 802.1X 认证。我现在寝室里用的 Buffalo WHR-HP-G54 上就使用此程序通过了学校的 802.1X 认证。然后再运行一个 mytunet 来打开网关上的出校访问权限。这样就可以在全天时间使用无线网络了。(熄灯停电时除外……)

这个 bugfix 我用了大半年了,还是比较顺利的。只是最近在恩山无线论坛上看到了很多人受困于 H3C 和锐捷的私有 802.1X 认证。于是有人打算在路由器上运行 Linux 版的认证程序从而通过校园网认证。无奈的是这个 bug 再一次阻止了一大部分人的企图…… 很多人新买的路由器比如 WHR-HP-G54、WL-520gU、WHR-G125 等都有 roboswitch 的身影,移植过来的认证程序在 PC 上跑跑当然可以,可惜是没有针对性地解决 Broadcom roboswitch 的问题。自然也逃不过此 bug 的追杀,恩山上铩羽而归的人不在少数。

幸运一些的人有两种可能。一种是使用的 Belkin 7231-4p(不管有没有经过恩山无线的改版)它使用了 ADM6996L 交换芯片,没有此问题。另外一种是像 felix021 同学那样的,虽然路由器是使用 BCM5354 芯片的 WL-520gU,但校园网认证协议使用广播包(MAC为 FF-FF-FF-FF-FF-FF)而不是多播包。所有的交换模块接到了广播包当然是无条件转发。因此也能顺利通过认证。

不幸运的该怎么办呢? 😈  可以移植 Jouke Witteveen 在 roboswitch 中使用过的方法,在私有协议的认证程序中加入 Broadcom 芯片的支持,则有希望通过认证了。我已经跟 Jouke Witteveen 取得联系,他毫无保留地提供了一份 leaked document 给我作参考,十分感谢。 🙂

PS: 发现 WordPress 链接到自己文章的时候会发送 pingback,看上去真傻……只好装了一个 No-self-ping 插件。