<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>delphij&apos;s Chaos</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/" />
<link rel="self" type="application/atom+xml" href="http://blog.delphij.net/atom.xml" />
<id>tag:blog.delphij.net,2007-09-28://2</id>
<updated>2009-06-28T03:30:13Z</updated>
<subtitle>选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……</subtitle>
<generator uri="http://www.sixapart.com/movabletype/">Movable Type Pro 4.261</generator>

<entry>
<title>27了，不能再假装年轻了</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/06/27.html" />
<id>tag:blog.delphij.net,2009://2.2004</id>

<published>2009-06-28T02:56:39Z</published>
<updated>2009-06-28T03:30:13Z</updated>

<summary>27了，不能再假装年轻了。...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Life" scheme="http://www.sixapart.com/ns/types#category" />


<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>27了，不能再假装年轻了。</p>]]>

</content>
</entry>

<entry>
<title>Heal The World (Lyrics)</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/06/heal-the-world.html" />
<id>tag:blog.delphij.net,2009://2.2003</id>

<published>2009-06-26T04:06:26Z</published>
<updated>2009-06-26T23:09:03Z</updated>

<summary>In memorial of Michael Jackson (1958.08.29 - 2009.06.25) &quot;Heal The World&quot; There&apos;s A Place In Your Heart And I Know That It Is Love And This Place Could Be Much Brighter Than Tomorrow And If You Really Try You&apos;ll Find...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Shared Chaos" scheme="http://www.sixapart.com/ns/types#category" />

<category term="michaeljackson" label="Michael Jackson" scheme="http://www.sixapart.com/ns/types#tag" />

<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
In memorial of Michael Jackson (1958.08.29 - 2009.06.25)

&quot;Heal The World&quot;

There&apos;s A Place In
Your Heart
And I Know That It Is Love
And This Place Could
Be Much
Brighter Than Tomorrow
And If You Really Try
You&apos;ll Find There&apos;s No Need
To Cry
In This Place You&apos;ll Feel
There&apos;s No Hurt Or Sorrow
There Are Ways
To Get There
If You Care Enough
For The Living
Make A Little Space
Make A Better Place...

Heal The World
Make It A Better Place
For You And For Me
And The Entire Human Race
There Are People Dying
If You Care Enough
For The Living
Make A Better Place
For You And For Me

If You Want To Know Why
There&apos;s A Love That
Cannot Lie
Love Is Strong
It Only Cares For
Joyful Giving
If We Try
We Shall See
In This Bliss
We Cannot Feel
Fear Or Dread
We Stop Existing And
Start Living

Then It Feels That Always
Love&apos;s Enough For
Us Growing
So Make A Better World
Make A Better World...

Heal The World
Make It A Better Place
For You And For Me
And The Entire Human Race
There Are People Dying
If You Care Enough
For The Living
Make A Better Place
For You And For Me

And The Dream We Were
Conceived In
Will Reveal A Joyful Face
And The World We
Once Believed In
Will Shine Again In Grace
Then Why Do We Keep
Strangling Life
Wound This Earth
Crucify Its Soul
Though It&apos;s Plain To See
This World Is Heavenly
Be God&apos;s Glow

We Could Fly So High
Let Our Spirits Never Die
In My Heart
I Feel You Are All
My Brothers
Create A World With
No Fear
Together We&apos;ll Cry
Happy Tears
See The Nations Turn
Their Swords
Into Plowshares

We Could Really Get There
If You Cared Enough
For The Living
Make A Little Space
To Make A Better Place...

Heal The World
Make It A Better Place
For You And For Me
And The Entire Human Race
There Are People Dying
If You Care Enough
For The Living
Make A Better Place
For You And For Me

Heal The World
Make It A Better Place
For You And For Me
And The Entire Human Race
There Are People Dying
If You Care Enough
For The Living
Make A Better Place
For You And For Me

Heal The World
Make It A Better Place
For You And For Me
And The Entire Human Race
There Are People Dying
If You Care Enough
For The Living
Make A Better Place
For You And For Me

There Are People Dying
If You Care Enough
For The Living
Make A Better Place
For You And For Me

There Are People Dying
If You Care Enough
For The Living
Make A Better Place
For You And For Me

You And For Me
You And For Me
You And For Me
You And For Me
You And For Me
You And For Me
You And For Me
You And For Me
You And For Me
You And For Me
You And For Me
</content>
</entry>

<entry>
<title>DNS安全：投毒攻击与缓存服务器的配置</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/06/dns-3.html" />
<id>tag:blog.delphij.net,2009://2.2002</id>

<published>2009-06-25T04:39:02Z</published>
<updated>2009-06-25T05:14:09Z</updated>

<summary>DNS是目前互联网上使用最为普遍，同时也是漏洞很多的一个协议。DNS投毒攻击（Poisoning）是一种比较常见的攻击手法，具体而言，通常一台 DNS 缓存服务器能够影响大量的客户机，通过投毒攻击，能够使得大量用户访问某个具体域名时得到不正确的结果（例如，钓鱼网站，等等）。 为了减少DNS投毒攻击的威胁，有两项非常重要的安全实践，其一是将权威DNS服务器（这些服务器负责解析某些特定的域名）与缓存 DNS 服务器（这些服务器负责代替其他机器解析域名，并将结果在其本地缓存，以减少权威 DNS 服务器负载和不必要的网络间流量）分开部署，并启用 DNSsec；其二，是限制 DNS 缓存服务器的可访问来源 IP，并在边界路由器上过滤来自不受信路由器，但来源 IP 字段是本网络的数据包。 由于 DNSsec 目前还没有被广泛部署，限制能够访问 DNS 缓存服务器的来源 IP 是缓存服务器配置的一项非常重要的部分。我们知道，UDP协议中，来源IP字段是可以伪造的（这也是为什么TCP协议要比UDP安全的原因，因为它使用三次握手机制来提高伪造来源 IP 的难度），而 DNS 协议的普通查询建立在 UDP 之上（这是出于显而易见的性能考虑；在实际实现中，许多 DNS 服务器支持以 TCP 方式进行查询），而其事务 ID 只有 16 个 bit，很容易伪造，因此，攻击者通过向 DNS 缓存服务器发出查询受害域名的请求包，并同时发送大量伪造的 DNS 回应，并在这些伪造回应中人为地设置较大的...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Security" scheme="http://www.sixapart.com/ns/types#category" />

<category term="bind" label="BIND" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="dns" label="DNS" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="security" label="Security" scheme="http://www.sixapart.com/ns/types#tag" />

<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>DNS是目前互联网上使用最为普遍，同时也是漏洞很多的一个协议。DNS投毒攻击（Poisoning）是一种比较常见的攻击手法，具体而言，通常一台 DNS 缓存服务器能够影响大量的客户机，通过投毒攻击，能够使得大量用户访问某个具体域名时得到不正确的结果（例如，钓鱼网站，等等）。</p>

<p>为了减少DNS投毒攻击的威胁，有两项非常重要的安全实践，其一是将权威DNS服务器（这些服务器负责解析某些特定的域名）与缓存 DNS 服务器（这些服务器负责代替其他机器解析域名，并将结果在其本地缓存，以减少权威 DNS 服务器负载和不必要的网络间流量）分开部署，并启用 DNSsec；其二，是限制 DNS 缓存服务器的可访问来源 IP，并在边界路由器上过滤来自不受信路由器，但来源 IP 字段是本网络的数据包。</p>

<p>由于 DNSsec 目前还没有被广泛部署，限制能够访问 DNS 缓存服务器的来源 IP 是缓存服务器配置的一项非常重要的部分。我们知道，UDP协议中，来源IP字段是可以伪造的（这也是为什么TCP协议要比UDP安全的原因，因为它使用三次握手机制来提高伪造来源 IP 的难度），而 DNS 协议的普通查询建立在 UDP 之上（这是出于显而易见的性能考虑；在实际实现中，许多 DNS 服务器支持以 TCP 方式进行查询），而其事务 ID 只有 16 个 bit，很容易伪造，因此，攻击者通过向 DNS 缓存服务器发出查询受害域名的请求包，并同时发送大量伪造的 DNS 回应，并在这些伪造回应中人为地设置较大的 TTL，就很有机会"污染"缓存 DNS 服务器的本地缓存，并在其中长期滞留，从而达到影响更多客户机的目的。</p>

<p>针对 DNS 投毒攻击，目前并没有真正的遏制方法，所有采取的措施，包括 DNS 缓存服务器的查询端口随机化等等，都只是将攻击者成功的机会减少一些量级。真正解决这类攻击的方法只有 DNSsec 和 IPsec。</p>

<p>对于企业网络管理员来说，通过在企业内部架设 DNS 缓存服务器并进行合理的配置，能够有效地减少 DNS 投毒攻击的风险。这类网络往往采用的是不被路由的 <a href="http://www.faqs.org/rfcs/rfc1918.html">RFC 1918</a> 内网 IP 地址，并通过 DHCP 来对客户机进行配置，因此可以通过后者来将客户机 DNS 指定为内部的 DNS 缓存服务器。具体来说，企业内部 DNS 应配置为只监听内网，同时在访问外网时，尽可能利用 NAT 机制对其访问源地址、源端口进行随机化处理。</p>

<p>有时，企业内部会希望有一些内部域名来方便员工访问一些内部的资源。习惯上，这些 NS 记录并不会对公网上的 DNS 服务器发布，因此，如果 DNS 缓存服务器没有设置上级 forwarder，就可能会无法解析这类域名。想要解决这个问题，最简单的办法就是配置一组 forward 域，例如，在 BIND 9.x 中，使用类似下面的设置：</p>

<pre>
zone "internal.example.com" {
    type forward;
    forward only;
    forwarders {
        172.16.2.53;
    };
};
</pre>

<p>在上面的配置中，当有用户请求 internal.example.com 下的域名，例如 www.internal.example.com 时，缓存服务器便会把请求直接转发给对应的 DNS 服务器， 172.16.2.53 （这个服务器应是 internal.example.com 的权威解析）了。</p>]]>

</content>
</entry>

<entry>
<title>Apache中同一IP多个HTTPS虚拟主机的实现</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/06/apacheiphttps.html" />
<id>tag:blog.delphij.net,2009://2.2001</id>

<published>2009-06-25T00:49:26Z</published>
<updated>2009-06-25T04:31:51Z</updated>

<summary>在 Apache 文档中提到，不能在单个 IP 上同时有多个按名字识别的虚拟主机(&quot;named virtual host&quot;)。不完全是这样。 HTTPS协议的过程是：服务器首先与客户机之间进行服务器身份验证并协商安全会话，然后，客户端向服务器发送 HTTP 请求。这样一来，在客户端开始发送请求之前，服务器就已经把证书发给了客户端（客户端根据本地的根证书去验证证书链，等等）。而最重要的是，为了表明身份，这个证书的周知名称（&quot;Common Name&quot;）填写的应该是域名，否则浏览器会给出警告。 既然在这个过程中，客户端就所访问的域名所处的地位是&quot;被告知&quot;的地位，因此，客户端再发出的 Host: 请求头也就显得不那么有意义了。另一方面，如果客户请求的域名与周知名称不符，浏览器也会给出警告。至少，在表面上看是这样。 不过，对于自行签署的证书，以及一些发证机构而言，其实还可以签署一种普适HTTPS证书，这种证书的周知名称一栏是 *.domain.tld 这样的形式，即其主机名部分可以是任意字符串，而只有域名部分是确定的。 当然，这种证书的安全性有一定的负面影响：由于一个证书可以验证整个域下面的所有服务器，一旦其被破解，则所有加密通讯也就同时失密了（当然，可以每台服务器使用自己的单独的证书），不过这个问题并不是太严重，通常还算是尚可接受的范围。另一个潜在的影响是，某些手机上运行的浏览器不能正确处理这种证书，不过这个问题仅限于希望给手机提供服务的网站。 因此，简而言之，符合这样几个条件的前提下，是可以在同一个IP上部署多个HTTPS虚拟主机的：a) 这些虚拟主机是同属于同一域名的子域名 b) 拥有普适证书 c) 正确地配置Apache。 Apache配置要点 在HTTPS(TCP 443)端口上配置NameVirtualHost，例如 NameVirtualHost *:443 为每个虚拟主机配置同样的 SSL 设置（事实上只有第一个会生效） 为每个虚拟主机配置对应的ServerName...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Security" scheme="http://www.sixapart.com/ns/types#category" />

<category term="apache" label="Apache" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="tls" label="TLS" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="作弊条" label="作弊条" scheme="http://www.sixapart.com/ns/types#tag" />

<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>在 Apache 文档中提到，<a href="http://httpd.apache.org/docs/2.2/ssl/ssl_faq.html#vhosts2">不能</a>在单个 IP 上同时有多个按名字识别的虚拟主机("named virtual host")。不完全是这样。</p>

<p>HTTPS协议的过程是：服务器首先与客户机之间进行服务器身份验证并协商安全会话，然后，客户端向服务器发送 HTTP 请求。这样一来，在客户端开始发送请求之前，服务器就已经把证书发给了客户端（客户端根据本地的根证书去验证证书链，等等）。而最重要的是，为了表明身份，这个证书的周知名称（"Common Name"）填写的应该是域名，否则浏览器会给出警告。</p>

<p>既然在这个过程中，客户端就所访问的域名所处的地位是"被告知"的地位，因此，客户端再发出的 Host: 请求头也就显得不那么有意义了。另一方面，如果客户请求的域名与周知名称不符，浏览器也会给出警告。至少，在表面上看是这样。</p>

<p>不过，对于自行签署的证书，以及一些发证机构而言，其实还可以签署一种普适HTTPS证书，这种证书的周知名称一栏是 *.domain.tld 这样的形式，即其主机名部分可以是任意字符串，而只有域名部分是确定的。</p>

<p>当然，这种证书的安全性有一定的负面影响：由于一个证书可以验证整个域下面的所有服务器，一旦其被破解，则所有加密通讯也就同时失密了（当然，可以每台服务器使用自己的单独的证书），不过这个问题并不是太严重，通常还算是尚可接受的范围。另一个潜在的影响是，某些手机上运行的浏览器不能正确处理这种证书，不过这个问题仅限于希望给手机提供服务的网站。</p>

<p>因此，简而言之，符合这样几个条件的前提下，是可以在同一个IP上部署多个HTTPS虚拟主机的：a) 这些虚拟主机是同属于同一域名的子域名 b) 拥有普适证书 c) 正确地配置Apache。</p>

<hr />

<p>Apache配置要点</p>

<ul>
	<li>在HTTPS(TCP 443)端口上配置NameVirtualHost，例如 NameVirtualHost *:443</li>
	<li>为每个虚拟主机配置同样的 SSL 设置（事实上只有第一个会生效）</li>
	<li>为每个虚拟主机配置对应的ServerName</li>
</ul>]]>

</content>
</entry>

<entry>
<title>驱动程序是什么</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/06/post-563.html" />
<id>tag:blog.delphij.net,2009://2.2000</id>

<published>2009-06-19T00:03:36Z</published>
<updated>2009-06-25T00:44:26Z</updated>

<summary>Disclaimer: 这是一篇科普文章，不会涉及太多的技术细节。 简单地说，驱动程序是操作系统与硬件（有时也包括其他的软件或在硬件上运行的firmware）之间的一种接口程序。对于操作系统来说，驱动程序是非常重要的 不过，在现代系统中，多数情况下，驱动程序并不只是简单机械地翻译操作系统的请求，更多的时候，驱动程序还有另外的很重要的作用，即绕过硬件本身的问题，常见的例如，临时加载一份较新版本的固件、针对某些版本的硬件禁用某些会导致问题的特性、分配内存的时候确保按边界对齐或只在前4GB分配以绕过DMA引擎寻址能力差的问题、通过增加延迟来解决硬件制造时对时序过于敏感的问题，等等。通过驱动程序绕过这些问题，能够让用户看不到（或者，至少在硬件负载不大的情况下看不到）问题的存在，并消除一小部分问题（例如原先随硬件发布的固件版本存在一些问题，而又没有提供更新固件的接口，新版本的驱动可能会在系统引导的过程中上传一份新版的固件到设备的临时存储）。 一般来说，驱动程序可以在逻辑上分为以下三个部分：...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="*nix and Win32 Kernel" scheme="http://www.sixapart.com/ns/types#category" />

<category term="driver" label="driver" scheme="http://www.sixapart.com/ns/types#tag" />

<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>Disclaimer: 这是一篇科普文章，不会涉及太多的技术细节。</p>

<p>简单地说，驱动程序是操作系统与硬件（有时也包括其他的软件或在硬件上运行的firmware）之间的一种接口程序。对于操作系统来说，驱动程序是非常重要的</p>

<p>不过，在现代系统中，多数情况下，驱动程序并不只是简单机械地翻译操作系统的请求，更多的时候，驱动程序还有另外的很重要的作用，即绕过硬件本身的问题，常见的例如，临时加载一份较新版本的固件、针对某些版本的硬件禁用某些会导致问题的特性、分配内存的时候确保按边界对齐或只在前4GB分配以绕过DMA引擎寻址能力差的问题、通过增加延迟来解决硬件制造时对时序过于敏感的问题，等等。通过驱动程序绕过这些问题，能够让用户看不到（或者，至少在硬件负载不大的情况下看不到）问题的存在，并消除一小部分问题（例如原先随硬件发布的固件版本存在一些问题，而又没有提供更新固件的接口，新版本的驱动可能会在系统引导的过程中上传一份新版的固件到设备的临时存储）。</p>

<p>一般来说，驱动程序可以在逻辑上分为以下三个部分：</p>]]>
<![CDATA[<p>识别／探测部分<p>

<p>这一部分的主要功能，是将OS提供的一系列资源描述所对应的设备与驱动程序本身携带的识别信息，对PC而言通常是一组PCI ID进行比对；如果匹配，驱动程序将告诉操作系统自己对设备"感兴趣"。</p>

<p>有时，对同一个设备"感兴趣"的驱动程序可能有多个。操作系统会按照一定的规则去选择其中的一个。以 <a href="http://www.FreeBSD.org/">FreeBSD</a> 为例，操作系统会根据探测函数返回的数值大小来决定最终由哪个驱动来接管设备。一些其他操作系统中，这个过程会由公共的代码以其他方式实现。</p>

<p>初始化部分</p>

<p>操作系统决定由某个具体的驱动接管设备之后，就调用驱动程序的初始化方法。驱动程序需要完成这么几个工作：</p>

<p>对硬件进行初始化。每个设备可能会有不同的初始化方法，这部分可能还需要担负更新固件、对设备进行一些设置等工作。此外，在这个阶段驱动程序也会从硬件中提取一些信息，例如其具体型号（特别是控制芯片的revision信息）等等。驱动程序还需要记录硬件对应的workaround信息，以备后续使用，并启用需要的workaround。</p>

<p>分配资源。包括用于进行DMA操作的描述符、缓冲区、中断，以及挂接在时钟处理程序上的一些定时处理程序。一些高吞吐量的设备，如网卡，可能会在这个阶段建立一系列工作线程。</p>

<p>通知操作系统和用户。例如，在控制台或日志中写入相关信息。这部分主要是便于查找问题。</p>

<p>操作翻译部分</p>

<p>这部分比较简单。一般来说，多数常见的硬件，如网卡、SCSI/SAS适配器、显卡等，都有与之对应的框架，而驱动程序要做的只是实现具体的方法。</p>]]>
</content>
</entry>

<entry>
<title>FreeBSD CLang/LLVM项目终于进svn了</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/06/freebsd-clangll.html" />
<id>tag:blog.delphij.net,2009://2.1999</id>

<published>2009-06-02T18:12:14Z</published>
<updated>2009-06-17T06:24:26Z</updated>

<summary>如题。 不过这一次因为-CURRENT code slush的缘故，应该不会在 8.0-CURRENT 里面引入了（Ed在svn里面建立了另一个branch来做）。我想从各方面考虑，9.0-RELEASE里面正式砍掉gcc那一套东西应该不会是很困难的事情。传统上 FreeBSD 的代码用到了很多gcc的扩展，因此可能还需要一段时间。 包含CLang的FreeBSD -CURRENT可以在 projects/clangbsd/ checkout。包含 CLang 的 LLVM 预计将能够在今年9月正式发布。...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="*nix and Win32 Kernel" scheme="http://www.sixapart.com/ns/types#category" />

<category term="clang" label="CLang" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="freebsd" label="FreeBSD" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="llvm" label="LLVM" scheme="http://www.sixapart.com/ns/types#tag" />

<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>如题。</p>

<p>不过这一次因为-CURRENT code slush的缘故，应该不会在 8.0-CURRENT 里面引入了（Ed在svn里面建立了另一个branch来做）。我想从各方面考虑，9.0-RELEASE里面正式砍掉gcc那一套东西应该不会是很困难的事情。传统上 FreeBSD 的代码用到了很多gcc的扩展，因此可能还需要一段时间。</p>

<p>包含CLang的FreeBSD -CURRENT可以在 projects/clangbsd/ checkout。包含 CLang 的 LLVM 预计将能够在今年9月正式发布。</p>]]>

</content>
</entry>

<entry>
<title>绝对外行才会说和相信&quot;绝对安全&quot;这种说法</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/05/post-562.html" />
<id>tag:blog.delphij.net,2009://2.1998</id>

<published>2009-05-19T22:19:41Z</published>
<updated>2009-05-22T00:27:08Z</updated>

<summary>我今天话放这儿。...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Security" scheme="http://www.sixapart.com/ns/types#category" />


<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>我今天话放这儿。</p>]]>

</content>
</entry>

<entry>
<title>实现安全的三种途径</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/05/post-561.html" />
<id>tag:blog.delphij.net,2009://2.1997</id>

<published>2009-05-12T20:52:30Z</published>
<updated>2009-05-13T01:04:19Z</updated>

<summary>回国的时候和 康神 及端木吃饭的时候聊起过这个话题，这里整理出来。 实现安全有三种主要的手法：基于隐蔽的安全（或者，基于假象的安全）、基于默认配置的安全和基于设计的安全。 基于假象的安全很容易理解，也很容易实现。举一个简单的例子，在一片西瓜地前面戳一块牌子，说这块西瓜地里有一个西瓜里面注射了剧毒。 可以想象，由于信息的不对称（不知道是哪个西瓜有毒，或者根本就没有西瓜有毒），试图偷西瓜的人就会有所忌惮----如果偷走的西瓜含有剧毒，那么这个西瓜是没办法吃的。然而，这样做有至少三个很致命的弱点：首先，为了实现最大化的利益，很可能瓜地的主人并不真的注射剧毒（或者反过来说，把偷瓜的人毒死并不是他的目的，他的目的是尽可能地保护瓜不被偷）；其次，即使瓜地的主人真的只给一个西瓜注射了剧毒，那么如果有人偷了那个西瓜并且死掉，那么知道这件事的人就可以冲过来直接把所有的西瓜偷走；最后，一个以牙还牙的小偷，很可能会在牌子上留下这么一段话：现在有两个了...... 简单地说，基于假象或隐蔽的安全，建立在&quot;别人不知道其机制&quot;的基础上。这样的做法有时能够在一定程度上延缓攻击，但并不能使攻击的成功率降低。将弱点隐蔽这种方法成本比较低，例如，把门钥匙放在门框上、将知名服务端口如ssh（tcp/22）转到不知名端口如tcp/12580上、port knocking技术，以及国内银行常用的Active X插件等等。然而，假象终归是假象，这些方法都不能真正改善系统的安全性。这类做法，充其量只能作为没有其他更好的办法时候的一种临时 workaround，而不能带来长久的安全。 第二种做法，也就是基于默认配置的安全，是一类非常常见的策略。这种做法通常与其他安全机制合并使用。简单地说，采用这种策略的系统，在其出厂的时候是没有暴露在外的弱点的，例如它可能只开启了非常少量，甚至完全不开启任何服务，随后，管理员可以根据需要进行配置来开放一些需要的服务。...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Security" scheme="http://www.sixapart.com/ns/types#category" />

<category term="principals" label="principals" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="security" label="security" scheme="http://www.sixapart.com/ns/types#tag" />

<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>回国的时候和 <a href="http://blog.kangkang.org/">康神</a> 及端木吃饭的时候聊起过这个话题，这里整理出来。</p>

<p>实现安全有三种主要的手法：基于隐蔽的安全（或者，基于假象的安全）、基于默认配置的安全和基于设计的安全。</p>

<p>基于假象的安全很容易理解，也很容易实现。举一个简单的例子，在一片西瓜地前面戳一块牌子，说这块西瓜地里有一个西瓜里面注射了剧毒。</p>

<p>可以想象，由于信息的不对称（不知道是哪个西瓜有毒，或者根本就没有西瓜有毒），试图偷西瓜的人就会有所忌惮----如果偷走的西瓜含有剧毒，那么这个西瓜是没办法吃的。然而，这样做有至少三个很致命的弱点：首先，为了实现最大化的利益，很可能瓜地的主人并不真的注射剧毒（或者反过来说，把偷瓜的人毒死并不是他的目的，他的目的是尽可能地保护瓜不被偷）；其次，即使瓜地的主人真的只给一个西瓜注射了剧毒，那么如果有人偷了那个西瓜并且死掉，那么知道这件事的人就可以冲过来直接把所有的西瓜偷走；最后，一个以牙还牙的小偷，很可能会在牌子上留下这么一段话：现在有两个了......</p>

<p>简单地说，基于假象或隐蔽的安全，建立在"别人不知道其机制"的基础上。这样的做法有时能够在一定程度上延缓攻击，但并不能使攻击的成功率降低。将弱点隐蔽这种方法成本比较低，例如，把门钥匙放在门框上、将知名服务端口如ssh（tcp/22）转到不知名端口如tcp/12580上、<a href="http://www.portknocking.org/">port knocking</a>技术，以及国内银行常用的Active X插件等等。然而，假象终归是假象，这些方法都不能真正改善系统的安全性。这类做法，充其量只能作为没有其他更好的办法时候的一种临时 workaround，而不能带来长久的安全。</p>

<p>第二种做法，也就是基于默认配置的安全，是一类非常常见的策略。这种做法通常与其他安全机制合并使用。简单地说，采用这种策略的系统，在其出厂的时候是没有暴露在外的弱点的，例如它可能只开启了非常少量，甚至完全不开启任何服务，随后，管理员可以根据需要进行配置来开放一些需要的服务。</p>]]>
<![CDATA[<p>基于默认配置的安全可以说是"授权最小化"原则的一个延伸。在一个安全系统中，通过特权拆分等方式实现授权最小化之余，还可以使用默认配置安全的方法来减少用户配置安全系统的风险。采用这种策略的产品往往会要求用户告诉系统这个系统将如何使用，而不是让用户告诉这个系统将不会如何使用，典型的例子有 Windows Server 2003、<a href="http://www.openbsd.org/">OpenBSD</a> 等等。</p>

<p>基于设计的安全，是成本相对比较高，但效果也最好的一种做法。这种做法的要点是分析系统中的每一个可能的弱点，并采取适当的方法来消除弱点，或至少限制成功攻击可能带来的损失。例如在ssh中采用的使用特权拆分的做法，将处理输入的进程的特权抛弃，并使用DFA限制非特权进程向特权进程递交请求的类型，以公钥验证替代基于密码的验证措施，而不是强制使用20位以上的密码，以及采用更好的密码技术，都属于这一类方法。</p>

<p>基于设计的安全能够从根本上提高系统的安全性。然而，这一类的改进往往需要更多的安全知识和开发成本。在设计系统的过程中就将安全融入进去，往往要比在现有的系统中引入安全要容易得多，因为一些设计很可能会需要改变用户的使用习惯（例如，使用密码验证的用户可能必须携带包含自己私钥的证书或其他信任状才能登录），而用户的使用习惯往往又是保证整个系统安全的真正关键所在，因为一个好的系统必须优先保证它可以控制的部分的安全性，无论它是否被正确使用，而用户显然是不受这些系统控制的。</p>

<p>在实际的系统中，后两种方法往往会结合使用。基于假象的安全应该尽量避免使用，因为这种做法只会麻痹用户，让他们认为系统是安全的而放松警惕，而在好的安全系统中，用户恰恰是安全最薄弱的环节。</p>]]>
</content>
</entry>

<entry>
<title>LLVM: 为什么你需要关注这个项目</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/05/llvm.html" />
<id>tag:blog.delphij.net,2009://2.1996</id>

<published>2009-05-03T06:14:00Z</published>
<updated>2009-05-11T15:56:13Z</updated>

<summary>LLVM 是 Illinois 大学发起的一个开源项目，它到底是什么呢？从字面上看，它是一个虚机系统，然而这又和之前为大家所熟知的 JVM 以及 .net Runtime 这样的虚机不同，它提供了一套中立的中间代码和编译基础设施，并围绕这些设施提供了一套全新的编译策略（使得优化能够在编译、连接、运行环境执行过程中，以及安装之后以有效的方式进行）和其他一些非常有意思的功能。 为什么这个项目很重要呢？对于普通的开发人员来说，LLVM计划提供了越来越多的可以使用、编译器以外的其他工具。例如代码静态检查工具 LLVM/Clang Static Analyzer，是一个 Clang 的子项目，能够使用同样的 Makefile 生成 HTML 格式的分析报告；而对关注编译技术的开发人员来说，LLVM提供了很多优点：...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Development" scheme="http://www.sixapart.com/ns/types#category" />

<category term="llvm" label="LLVM" scheme="http://www.sixapart.com/ns/types#tag" />

<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p><a href="http://www.llvm.org/">LLVM</a> 是 Illinois 大学发起的一个开源项目，它到底是什么呢？从字面上看，它是一个虚机系统，然而这又和之前为大家所熟知的 JVM 以及 .net Runtime 这样的虚机不同，它提供了一套中立的中间代码和编译基础设施，并围绕这些设施提供了一套全新的编译策略（使得优化能够在编译、连接、运行环境执行过程中，以及安装之后以有效的方式进行）和其他一些非常有意思的功能。</p>

<p>为什么这个项目很重要呢？对于普通的开发人员来说，LLVM计划提供了越来越多的可以使用、编译器以外的其他工具。例如代码静态检查工具 <a href="http://clang.llvm.org/StaticAnalysis.html">LLVM/Clang Static Analyzer</a>，是一个 Clang 的子项目，能够使用同样的 Makefile 生成 HTML 格式的分析报告；而对关注编译技术的开发人员来说，LLVM提供了很多优点：</p>]]>
<![CDATA[<ul>
	<li>现代化的设计：LLVM的设计是高度模块化的，使得其代码更为清晰和便于排查问题所在。</li>
	<li>语言无关的中间代码：这使得透过LLVM能够将不同的语言相互连结起来；另一方面，这也使得LLVM能够紧密地与IDE交互和集成。另一方面，发布中间代码而非目标代码能够在目标系统上更好地发挥其潜能而又不伤害可调试性（i.e. 在目标系统上针对本机的硬件环境产生目标代码，但又能够直接通过中间代码来进行行级调试）</li>
	<li>作为工具和函数库：使用LLVM提供的工具可以比较容易地实现新的编程语言的优化编译器或VM，或为现有的编程语言引入一些更好的优化／调试特性。</li>
</ul>

<p>一些值得关注的基于LLVM的项目：</p>

<p><a href="http://clang.llvm.org">CLang</a> C／ObjC／C++ 编译器。目前C++部分还需要很多工作，但C的部分已经比较成熟了。这个项目还有一个子项目是 <a href="http://clang.llvm.org/StaticAnalysis.html">LLVM/Clang Static Analyzer</a>。</p>

<p><a href="http://llvmruby.org/">llvmruby</a> 基于LLVM的一个Ruby实现。</p>

<p><a href="http://code.google.com/p/unladen-swallow/">Unladen Swallow</a> 是 <a href="http://www.google.com/">Google</a> 发起的，使用 LLVM 替换 <a href="http://www.python.org/">Python</a> VM 的项目，其目标是提供更好的性能。</p>

<p>LLVM项目还提供了一些针对有意使用LLVM来实现新的编译器／优化工具的开发人员的 <a href="http://llvm.org/docs/tutorial/">教程</a>。</p>]]>
</content>
</entry>

<entry>
<title>For 27 years...</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/04/for-27-years.html" />
<id>tag:blog.delphij.net,2009://2.1995</id>

<published>2009-04-20T15:08:57Z</published>
<updated>2009-04-20T15:11:51Z</updated>

<summary>&quot;For 27 years, Sun has stood for courage, innovation, a willingness to blaze trails, to envision and engineer the future.&quot; Good luck, Sun!...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Life" scheme="http://www.sixapart.com/ns/types#category" />

<category term="oracle" label="Oracle" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="sun" label="Sun" scheme="http://www.sixapart.com/ns/types#tag" />

<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>"For 27 years, Sun has stood for courage, innovation, a willingness to blaze trails, to envision and engineer the future."</p>

<p><a href="http://picasaweb.google.com/delphij/Sun#5314756973472719282"><img src="http://lh3.ggpht.com/_GjhT1syzPBQ/ScHPTv9fIbI/AAAAAAAAAa8/Qq512V-S2Mg/s128/DSC_6395.jpg" /></a></p>

<p>Good luck, Sun!</p>]]>

</content>
</entry>

<entry>
<title>美国运通(American Express)的年度对帐单</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/04/american-expres.html" />
<id>tag:blog.delphij.net,2009://2.1994</id>

<published>2009-04-09T07:19:39Z</published>
<updated>2009-04-09T07:55:35Z</updated>

<summary><![CDATA[可怕，很可怕。 其实也没啥，年度对帐单其实就是把月度对帐单里面的帐目做了一下summary，然后分门别类地把刷卡的明细排列出来，告诉你每个月花了多少钱，有多少调整金额和charge（我从来不相信国内某银行宣传材料上写的那种月底不把钱还清是好的理财策略的说法，无论如何不还清导致最终的还款现值pv都会比还清的高，所以这项几乎一定是 &lt; 0的）。 不过我比较好奇的是这么大量的数据是如何存储和查询的。难不成是事先查询好保存成一个待下载的数据吗？想想看，这么大用户量跟数据量（当然，热数据很少，而且访问模式其实和邮件比较类似），还是需要动些脑筋才能做好的，也许这也是当天交易只减信用额度而不反映到实时帐单上的原因。...]]></summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Life" scheme="http://www.sixapart.com/ns/types#category" />

<category term="银行" label="银行" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="分布式系统" label="分布式系统" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="帐单" label="帐单" scheme="http://www.sixapart.com/ns/types#tag" />

<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>可怕，很可怕。</p>

<p>其实也没啥，年度对帐单其实就是把月度对帐单里面的帐目做了一下summary，然后分门别类地把刷卡的明细排列出来，告诉你每个月花了多少钱，有多少调整金额和charge（我从来不相信国内某银行宣传材料上写的那种月底不把钱还清是好的理财策略的说法，无论如何不还清导致最终的还款现值pv都会比还清的高，所以这项几乎一定是 &lt; 0的）。</p>

<p>不过我比较好奇的是这么大量的数据是如何存储和查询的。难不成是事先查询好保存成一个待下载的数据吗？想想看，这么大用户量跟数据量（当然，热数据很少，而且访问模式其实和邮件比较类似），还是需要动些脑筋才能做好的，也许这也是当天交易只减信用额度而不反映到实时帐单上的原因。</p>]]>

</content>
</entry>

<entry>
<title>关于分治卖票协议的讨论</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/04/post-560.html" />
<id>tag:blog.delphij.net,2009://2.1993</id>

<published>2009-04-07T07:37:37Z</published>
<updated>2009-04-07T07:42:16Z</updated>

<summary>和蛇头GG讨论了一个关于卖票的问题，简单地说是票很有限，需求量很大，如何能够尽可能高效地让票以尽可能公平的方式卖出去。 我设计了一个分布式的结构来解决这个问题，当然这个原型可以进一步改进，此处按下不表。记录一下我对这个结构公平性的描述的一个比喻： &quot;因为其他人也hash了，或者换句话说，这个系统其实不介意一开始有人就注定拿不到票。 就跟一大群人排队抽签是一样的道理，其实这个就相当于说一帮人排队抽签决定去拿一个信封， 然后拿到空信封的可以重新排队抽签，要么拿到票。&quot; 这个系统其实要求参与进来的客户机一起参与计算（但是这些计算并不会明显加大服务器系统的负载），有一些能想到的缺陷，也许需要克服，也许根本不是问题？先把想法记下来再说。...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Others" scheme="http://www.sixapart.com/ns/types#category" />


<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>和蛇头GG讨论了一个关于卖票的问题，简单地说是票很有限，需求量很大，如何能够尽可能高效地让票以尽可能公平的方式卖出去。</p>

<p>我设计了一个分布式的结构来解决这个问题，当然这个原型可以进一步改进，此处按下不表。记录一下我对这个结构公平性的描述的一个比喻：</p>

<p>"因为其他人也hash了，或者换句话说，这个系统其实不介意一开始有人就注定拿不到票。 就跟一大群人排队抽签是一样的道理，其实这个就相当于说一帮人排队抽签决定去拿一个信封， 然后拿到空信封的可以重新排队抽签，要么拿到票。"</p>

<p>这个系统其实要求参与进来的客户机一起参与计算（但是这些计算并不会明显加大服务器系统的负载），有一些能想到的缺陷，也许需要克服，也许根本不是问题？先把想法记下来再说。</p>]]>

</content>
</entry>

<entry>
<title>十多年以后又做了一次FAT文件恢复</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/04/fat.html" />
<id>tag:blog.delphij.net,2009://2.1992</id>

<published>2009-04-07T06:47:20Z</published>
<updated>2009-04-07T06:59:06Z</updated>

<summary>今天又帮人做了一次恢复，上次干这个事是十几年前的事情了。数据恢复是个手艺活，恢复个60%-70%基本上靠工具，剩下的就靠运气和经验了。 想起很久以前做的一个小工具。简单地说是先把磁盘复制一份出来，然后在数据文件上去操作，把已知的链接上，然后把未知的文件的首簇、长度算出来，在空闲区里面找（很明显，大文件恢复的成功与否很大程度上取决于你多久整理一次磁盘以及是否经常删除文件）然后接个链出来。我当时很感激某文本编辑软件每次都会把之前的文件改名做BAK然后把文件整个重新写一遍。 我对做数据恢复这事是很反感的，总体而言。21世纪需要的是健壮的、支持事务和版本的文件系统。...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Life" scheme="http://www.sixapart.com/ns/types#category" />


<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>今天又帮人做了一次恢复，上次干这个事是十几年前的事情了。数据恢复是个手艺活，恢复个60%-70%基本上靠工具，剩下的就靠运气和经验了。</p>

<p>想起很久以前做的一个小工具。简单地说是先把磁盘复制一份出来，然后在数据文件上去操作，把已知的链接上，然后把未知的文件的首簇、长度算出来，在空闲区里面找（很明显，大文件恢复的成功与否很大程度上取决于你多久整理一次磁盘以及是否经常删除文件）然后接个链出来。我当时很感激某文本编辑软件每次都会把之前的文件改名做BAK然后把文件整个重新写一遍。</p>

<p>我对做数据恢复这事是很反感的，总体而言。21世纪需要的是健壮的、支持事务和版本的文件系统。</p>]]>

</content>
</entry>

<entry>
<title>Overhaul of libc Berkeley DB has been committed</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/03/overhaul-of-lib.html" />
<id>tag:blog.delphij.net,2009://2.1991</id>

<published>2009-03-28T07:47:11Z</published>
<updated>2009-03-28T08:11:13Z</updated>

<summary>First of all, thanks goes to all people who has helped me on this project, especially Pav (portmgr@) who gave it a twist on pointyhat. It seems that this has taken me almost a month and 20 commits to get...</summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Development" scheme="http://www.sixapart.com/ns/types#category" />

<category term="berkeleydb" label="BerkeleyDB" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="freebsd" label="FreeBSD" scheme="http://www.sixapart.com/ns/types#tag" />

<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>First of all, thanks goes to all people who has helped me on this project, especially Pav (portmgr@) who gave it a twist on pointyhat.</p>

<p>It seems that this has taken me almost a month and 20 commits to get into the tree, after the code is ready.  At the beginning, the changeset was ~200KB, and I believe it's not good to just go ahead and commit it in one time, since it makes reviewing hard.  Instead, I manually split it into smaller, functional related chunks, and commit it part-by-part.</p>

<p>The overhauled libc Berkeley DB code consists several enhancements.  First, almost all Berkeley DB 1.86 improvements has been merged, except their new hash routines which would introduce an unavoidable file format change which apparently does not make it a good candidate for FreeBSD libc.</p>

<p>There is a changeset that has changed mpool(3) interface.  I doubt if any application would make use of it but I provided a compatibility shim anyway.<p>

<p>Also, this changeset brings some security measurements that would reduce the risk of potential information leak.  When allocating data, the libc now requests zero'ed memory, and zero's buffer memory upon free().  While I believe it's the client program's responsibility to zero out any sensitive information, it looks like that this makes it harder to dump sensitive data "by accident".  Speaking of a reported security problem about postfix, it seems that the zero-before-free is more useful to mitigate the situation.</p>

<p>This overhaul also brought several memory leak fixes and crash fixes.</p>]]>

</content>
</entry>

<entry>
<title>如何：转换旧式编码的MySQL数据库到UTF-8</title>
<link rel="alternate" type="text/html" href="http://blog.delphij.net/archives/2009/03/mysqlutf-8.html" />
<id>tag:blog.delphij.net,2009://2.1990</id>

<published>2009-03-26T00:23:08Z</published>
<updated>2009-03-26T17:08:17Z</updated>

<summary><![CDATA[最近帮公司的一个客户做了一个数据库迁移，客户声称数据是 utf-8 的，然而在使用过程中出现了许多乱码，检查发现数据并非 utf-8，而是 utf-8 编码之后的 big5，而排序方式更是混乱不堪的默认的utf8-swedian-ci。 MySQL的国际化支持很差。MySQL从 4.1 版本开始大刀阔斧地进行了不兼容的改动，简单地说，这些改动让相当多的操作默认以UTF-8进行，然而这会给旧的应用程序带来很多问题。许多文献推荐使用 SET CHARACTER SET 作为 workaround，尽管这能够解决一些问题，但这种做法本质上会导致 MySQL 进行额外的转换，因此并不是十分理想。 正确的方法是把所有的东西都转换成 UTF-8。一个比较常见的错误是使用SET NAMES UTF8并直接从原始的 Big5 表中导出。这种情况下，文字会被以UTF-8编码的big5方式保存。比较简单的做法是将其直接导入数据表，并以 latin-1 导出： mysqldump -u 用户名 -p密码 --skip-extended-insert --default-character-set=latin1 --databases 数据库名 &gt; big5.sql 接着，使用 piconv （随 Perl 提供）来转换编码。我个人认为这个工具比...]]></summary>
<author>
<name>Xin LI</name>
<uri>http://www.delphij.net/</uri>
</author>

<category term="Development" scheme="http://www.sixapart.com/ns/types#category" />

<category term="convert" label="convert" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="i18n" label="i18n" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="mysql" label="MySQL" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="unicode" label="unicode" scheme="http://www.sixapart.com/ns/types#tag" />
<category term="utf8" label="utf-8" scheme="http://www.sixapart.com/ns/types#tag" />

<content type="html" xml:lang="en" xml:base="http://blog.delphij.net/">
<![CDATA[<p>最近帮公司的一个客户做了一个数据库迁移，客户声称数据是 utf-8 的，然而在使用过程中出现了许多乱码，检查发现数据并非 utf-8，而是 utf-8 编码之后的 big5，而排序方式更是混乱不堪的默认的utf8-swedian-ci。</p>

<p>MySQL的国际化支持很差。MySQL从 4.1 版本开始大刀阔斧地进行了不兼容的改动，简单地说，这些改动让相当多的操作默认以UTF-8进行，然而这会给旧的应用程序带来很多问题。许多文献推荐使用 SET CHARACTER SET 作为 workaround，尽管这能够解决一些问题，但这种做法本质上会导致 MySQL 进行额外的转换，因此并不是十分理想。</p>

<p>正确的方法是把所有的东西都转换成 UTF-8。一个比较常见的错误是使用SET NAMES UTF8并直接从原始的 Big5 表中导出。这种情况下，文字会被以UTF-8编码的big5方式保存。比较简单的做法是将其直接导入数据表，并以 latin-1 导出：</p>

<p>mysqldump -u 用户名 -p密码 --skip-extended-insert  --default-character-set=latin1 --databases 数据库名 &gt; big5.sql</p>

<p>接着，使用 piconv （随 Perl 提供）来转换编码。我个人认为这个工具比 uconv 和 iconv 都要好。</p>

<p>piconv -f big5 -t utf8 &lt; big5.sql &gt; utf8.sql</p>

<p>接下来要把 utf8.sql 中的 latin1 等不正确的编码改为 utf8（通常，简单地sed即可）</p>

<p>最后重新导入。前面 skip-extended-insert 可以让发生错误时显示较具体的行号，这对于较大的数据库而言会比较方便。</p>

<p>声明：此 HOWTO 文档以现状方式提供，不提供任何担保。此文档为个人作弊条，本人会对部分疑问进行解释，但同样不提供任何保证。</p>

<p>此篇按下述授权发表：</p>

<p>/*-<br>
 * Copyright (c) 2009 Xin LI &lt;delphij@FreeBSD.org&gt;<br />
 * All rights reserved.<br />
 *<br />
 * Redistribution and use in source and binary forms, with or without<br />
 * modification, are permitted provided that the following conditions<br />
 * are met:<br />
 * 1. Redistributions of source code must retain the above copyright<br />
 *&nbsp;&nbsp;&nbsp;&nbsp;notice, this list of conditions and the following disclaimer.<br />
 * 2. Redistributions in binary form must reproduce the above copyright<br />
 *&nbsp;&nbsp;&nbsp;&nbsp;notice, this list of conditions and the following disclaimer in the<br />
 *&nbsp;&nbsp;&nbsp;&nbsp;documentation and/or other materials provided with the distribution.<br />
 *<br />
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND<br />
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE<br />
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE<br />
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE<br />
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br />
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS<br />
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)<br />
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT<br />
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY<br />
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF<br />
 * SUCH DAMAGE.<br />
 *<br />
 */</p>]]>

</content>
</entry>

</feed>