2008年8月30日星期六

TTS的口音

前几天装了日文的TTS引擎,然后用不同的TTS引擎说同一段话,恩,很有地方风味呢
原文是这个,Spring的JavaDoc里随便找到

This interface is implemented by objects that hold a number of bean definitions, each uniquely identified by a String name.

声音文件在这里:
http://bbs.cfan.com.cn/attachment.php?aid=242995

行程确定

2号的火车……凌晨4点就要开始……算上中间倒车的时间,这次估计要超过36小时了= =
PS:值得一提的是,这次买到的车票是4车厢1号,话说前面3个车厢应该是邮车啥的……没准是一趟火车的第一个座位,lucky~

血的教训告诉我们:最好不要多线程共享一个数据库连接

今天遇到一个奇怪的问题,有一段程序,会被多个线程并行访问,因为没有涉及到数据库写操作,所以就偷懒共享了一个DAO,但是发现一旦并发线程超过2个,就会出现异常,而且还是很奇怪的异常,好像是说数据库没有响应。调试了半天没发现什么问题,后来把DAO对象设置成了ThreadLocal,问题消失了……看来用一个数据库连接最好不要被多个线程同时操作。
最近经常在多线程同步上出问题,上午的时候出现了一个锁死的问题:有一个调用在一个同步块里面锁死了(因为另一个线程异常退出了,没有给这个线程解锁)然后后面紧跟着所有线程都停在了同步块上。在Profiler里一片红红的,好不壮观。
话说今天这个锁死的解决多亏了jconsoler和jvisualvm,这两个工具是最新的几个JDK版本才提供的,他们提供了对Java应用程序的本地或远程的即使监视和分析的功能。jconsole可以把每个线程的运行状态和阻塞原因打印出来,配合jvisualvm的可视化线程图表就可以确定到底是那个(些)线程进行了锁死,并有针对性的进行修复。
再废话一句:这两个工具好像都是基于JMX的,所以说JMX真是个好物啊~~

牢骚:最近Blogger确实有问题

不知道是ISP的问题还是Blogger本身的问题……每次访问Blogger的控制台就被断开连接,症状和被墙了一样……郁闷。但是访问我的Blog域名却没什么问题……更加郁闷。
每次想写点什么东西的时候,被这个错误弄得没什么心情写了。牢骚完毕。

2008年8月24日星期日

JMX-RMI

最近发现JMX是个好东西,很适用于分布式系统的控制信息传递。

/*
 * Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
 * Release under GNU/GPL Version 2.
 */
package jmxtest;

import java.rmi.registry.LocateRegistry;
import java.util.HashMap;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.remote.JMXAuthenticator;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import javax.security.auth.Subject;

/**
 *
 * @author Bearice
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws Exception {
        LocateRegistry.createRegistry(8877);
        MBeanServer server = MBeanServerFactory.createMBeanServer();
        ObjectName helloName = new ObjectName("hello:name=hello");
        HelloWorld hello = new HelloWorld();
        HashMap prop = new HashMap();
        prop.put(JMXConnectorServer.AUTHENTICATOR, new JMXAuthenticator() {

            public Subject authenticate(Object credentials) {
                System.out.println(credentials);
                if (credentials instanceof String) {
                    if (credentials.equals("hello")) {
                        return new Subject();
                    }
                }
                throw new SecurityException("not authicated");
            }
        });
        JMXConnectorServer cserver =
                JMXConnectorServerFactory.newJMXConnectorServer(
                new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:8877/hello"), prop, server);
        cserver.start();
        server.registerMBean(hello, helloName);
        for (ObjectInstance object : server.queryMBeans(null, null)) {
            System.out.println(object.getObjectName());
        }
        System.out.println(hello);
        System.out.println("start.....");
    }
}

/*
 * Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
 * Release under GNU/GPL Version 2.
 */
package jmxtest;

import java.util.HashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.JMX;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

/**
 *
 * @author Bearice
 */
public class Client {

    static HelloWorldMBean hello;

    public static void main(String[] args) throws Exception {
        final AtomicInteger count = new AtomicInteger();
        HashMap prop = new HashMap();
        prop.put(JMXConnector.CREDENTIALS, "hello");
        final JMXConnector conn = JMXConnectorFactory.connect(new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:8877/hello"), prop);
        conn.connect();
        Runnable r = new Runnable() {

            public void run() {
                for (int i = 0; i < 10; i++) {
                    try {
                        final HelloWorldMBean hello = JMX.newMBeanProxy(conn.getMBeanServerConnection(), new ObjectName("hello:name=hello"), HelloWorldMBean.class);
                        hello.setName("bearice");
                        hello.sayHello();
                        hello.getHelloString();
                        System.out.println(count.incrementAndGet());
                        Client.hello = hello;
                        System.out.println(hello.equals(hello.getThis()));
                    } catch (Exception ex) {
                        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        };
        Thread[] ts = new Thread[5];
        for (int i = 0; i < ts.length; i++) {
            ts[i] = new Thread(r);
            ts[i].start();
        }
        for (Thread t : ts) {
            t.join();
        }
        System.out.println(hello.equals(hello.getThis()));
        System.out.println(hello.getId());
        System.out.println(hello);
    }
}

/*
 * Copyrights (C) 2008 Bearice (Bearice@Gmail.com)
 * Release under GNU/GPL Version 2.
 */
package jmxtest;

import java.io.Serializable;

/**
 *
 * @author Bearice
 */
public interface HelloWorldMBean extends Serializable {

    void setName(String name);

    String getName();

    void sayHello();

    String getHelloString();

    int getId();

    @Override
    String toString();

    @Override
    int hashCode();

    @Override
    boolean equals( Object obj);
    
    HelloWorldMBean getThis();
}
class HelloWorld implements HelloWorldMBean, Serializable {

    static AtomicInteger count = new AtomicInteger();
    private static final long serialVersionUID = 1627976932729278650L;
    int id = count.incrementAndGet();
    String name;

    public synchronized void setName(String name) {
        this.name = name;
    }

    public synchronized String getName() {
        return name;
    }

    public synchronized void sayHello() {
        System.out.println(getHelloString());
    }

    public synchronized String getHelloString() {
        return "Hello, " + name;
    }

    public synchronized int getId() {
        return id;
    }

    public HelloWorldMBean getThis() {
        return this;
    }
}

忙里偷闲

最近发现Blogger总是断开连接,难道又被墙了,现在是开着无界上来发东西,不然就会出Connection Reset。不知道是为什么。
早上听过一个笑话,说坐火车要检查身份证,有一个哥们没带。售票员就建议说:“你跟那个查身份证的说‘李[哔]志是个王[哔]蛋’他就让你过去了。”那人就这么做了,的确让他过去了。
顺便说一句,上面讲的笑话是一件真实发生的事情= =||

2008年8月19日星期二

[FWD]如何忽略防火长城

原文地址:http://www.yeeyan.com/articles/view/40085/11992
翻译: 万柳烈士旅 
简介
本文从TCP/IP协议安全性的角度对中国防火墙系统的工作原理、工作特性和潜在的漏洞、造成的问题进行了详尽的调查和分析,并从多个角度提出了针对特别是防火长城这类利用TCP/IP协议进行攻击的反制措施。

如何忽略防火长城

Richard Clayton, Steven J. Murdoch, and Robert N. M. Watson*
University of Cambridge, Computer Laboratory, William Gates Building, 15 JJ Thomson Avenue, Cambridge CB3 0FD, United Kingdom
{richard.clayton, steven.murdoch, robert.watson}@cl.cam.ac.uk
* 致谢:我们感谢一位中国公民的帮助。(我们不会透露他的名字,他对我们实验的本质完全不知情,他的网页也不包含任何非法内容)他为我们理论思考提供了极为 可信的实践材料。Richard Clayton正为Intel Research资助的spamHINTS项目工作。Steven J. Murdoch由OpenNet Initiative资助。

摘要: 所谓“防火长城”之部分工作原理即是检测传输控制协议(TCP)报文中需要封锁的关键词。如果出现关键词,TCP复位报文(即RST标志置位的报文)即向 连接两端发送,连接随之关闭。而原报文完好通过防火墙,如果双方完全忽略防火墙的复位,那么连接仍可顺畅进行而防火墙失效。一旦连接被封锁,防火墙还会进 而尝试封锁双方的继发连接。后种特性可能被利用来对第三方进行拒绝服务攻击。

1 引言

中华人民共和国运行的互联网过滤系统,普遍认为是世界上最复杂的系统之一。[1]其部分工作原理即是检测网络(HTTP)流量判断是否出项特定关键词。[2]这些关键词涉及一些中国政府封杀的组织、不可接受的政治意识形态、不愿讨论的历史事件。[3]
直观判断,关键词封锁发生在连接中国与外界网络的路由器组内部。[4]这些路由器利用基于入侵检测系统(IDS)技术的设备来判断报文内容是否匹配中国政府制订的过滤规则。[5]如果客户端与服务器的一个连接需要封锁,路由器则会在数据流中注入伪TCP复位报文,于是双方便会断开连接。[6]这种封锁一旦触发,便会持续数分钟,相同方向上的继发连接都会被伪复位直接打断。
在本文第2节我们将讨论国家阻止其公民访问特定网络内 容的方法,以及以往调查者认定的优点和缺点。在第3节我们提供了从中国防火墙系统封锁的连接两端获取的一组报文。第4节我们提出了这个防火墙的一个模型, 来解释我们获得的结果。然后第5节我们将展示,通过忽略防火墙发出的TCP复位我们成功传输了本来应该被封锁的内容,并讨论为什么这种手段防火墙难以应 付。第6节我们展示了防火墙的封锁行为如何可以被利用来对第三方进行拒绝服务攻击。最后在第7节,我们讨论了这种规避审查的方法的优缺点,并思考了中国以 外的网站如何免于封锁降低访问难度,还提出公共政策能怎样鼓励人们规避审查的问题。

2 内容封锁系统

有三种显著的内容封锁手段:报文丢弃、DNS污染、内容检测。研究北威州封锁右翼纳粹内容的Dornseif的论文[7],和研究英国电信混合封锁系统封锁恋童癖网站的Clayton[8]的论文,一起确定了以上手段。

2.1 报文丢弃方案

在一种报文丢弃方案中,往特定IP地址的所有流量被全部丢弃,于是网站便无法访问。这种方案费用低廉,易于实施──标准的防火墙和路由器便已提供这些必要特性。报文丢弃方案有两个主要问题。首先,IP地址列表必须保持最新,如果内容提供者不想让ISP轻易封锁他们的网站,保持更新的困难便暴露出来。[9]其次,系统会导致“过度封锁”──共用同一IP的其他网站被全部封锁。Edelman调查了过度封锁的潜在程度,发现69.8%的.com、.org和.net网站与50以上其他网站共用IP。[10](虽然一部分域名只是“停放”在一个普通网页上)其详细数字显示网站共用IP数的连续变化图谱,反映出在一台主机上尽量多挂网站这种盛行的商业做法。

2.2 DNS污染方案

在一种DNS污染方案中,当用户查询域名服务系统(DNS)将文字的域名转换为数字的IP地址时,可以返回错误的应答或者不返回应答导致用户不能正 常访问。这类方案没有过度封锁的问题,因为禁止访问特定网站不会影响到其他网站。不过,邮件传递也需要DNS查询,如果只是封锁网站而不封锁邮件服务的 话,此类方案实现起来容易出错。Dornseif展示的样本中所有的ISP都至少有一次在实现DNS污染时出错。[11]

2.3 内容检测方案

多数内容检测方案是让所有流量通过一个代理服务器。这个代理通过不提供禁止内容来过滤。这种系统可以做得非常精确,程度可以到屏蔽单个网页或者单个图像而让其他内容顺利通过。这类基于代理的系统没有普遍使用的原因是,可以应付主干网络或者整个国家网络流量的系统过于昂贵。2004年9月美国宾夕法尼亚州,要求封锁包含儿童色情网站的一条州法令以违宪被裁定无效[12]。当初由于经费原因,宾夕法尼亚的ISP采用的是报文丢弃和DNS污染的混合策略,导致的过度封锁和“前置审核限制”对地区法庭作此裁决起到了相当的作用。不过,基于代理的系统已被部署到若干国家比如沙特阿拉伯[13]、缅甸[14],以及挪威的一些网络提供商比如Telenor[15]。Clayton研究的英国电信的系统是一种混合设计,利用廉价缓存代理处理特定目标IP的报文。不幸这导致用户可以逆向工程得到封禁网站的列表,而这些网站提供儿童的非法图像,这违背了此系统的公共政策目标。
进行内容检测的另一种手段则是入侵检测系统(IDS)。IDS设备可以检测通过的网络流量并判断其内容是否可接受。如果需要封禁则会调度邻近的防火墙拦截报文,或者就中国的情况而言,发送TCP复位报文导致威胁性连接关闭。基于IDS的系统显然比其他方案更灵活,更难规避。Dornseif和Clayton都对如何规避各种封锁进行了深入探讨。[16]然而如果通信保持清晰不加密不变形到IDS无法辨别的程度,那么无论采取什么规避手段,IDS方法都能够将其检测出来。[17]

3 中国防火墙如何封锁连接

我们在实验中从英国剑桥(墙外)的若干机器连接了中国内的一个网站(墙内)。当前中国的防火墙系统的工作方式是完全对称的[18]──在两个方向上检测内容并进行过滤。[19]通 过从剑桥的终端发出所有的指令我们完全避免了违反中国法律的可能性。一开始我们以正常模式访问一个中国网页并记录双方的报文流。接下来我们又发起一次有意 触发封禁的请求,观察连接是如何被复位报文关闭的。我们继续“正常”的(不包含触发性词汇的)请求,却发现接下来的连接都意外地被封锁了。接下来我们将详 细描述观测结果。

3.1 复位封锁

刚开始我们只是访问一个普通网页,如预期得到完全正常的返回。如下面的转储报文所示,起始的TCP三次握手(SYN[20],SYN/ACK[21],ACK[22]) 之后客户端(此实例中使用了53382端口)向服务端http端口(tcp/80)发出了超文本传输协议(HTTP)的GET指令获取顶级页面(/),传 输正常。我们使用netcat(nc)发出这个请求,没有使用网页浏览器,从而避免了无关细节。报文用ethereal截取,用一般格式表示出来。
cam(53382) → china(http) [SYN]
china(http) → cam(53382) [SYN, ACK]
cam(53382) → china(http) [ACK]
cam(53382) → china(http) GET / HTTP/1.0
china(http) → cam(53382) HTTP/1.1 200 OK (text/html) ……
china(http) → cam(53382) ……其余页面内容
cam(53382) → china(http) [ACK]
……接下来这个页面就完整了。
我们发出另一个请求,包含了一小段可能触发封禁的文字,当然这也很快发生了:
cam(54190) → china(http) [SYN]
china(http) → cam(54190) [SYN, ACK] TTL=39
cam(54190) → china(http) [ACK]
cam(54190) → china(http) GET /?falun HTTP/1.0
china(http) → cam(54190) [RST] TTL=47, seq=1, ack=1
china(http) → cam(54190) [RST] TTL=47, seq=1461, ack=1
china(http) → cam(54190) [RST] TTL=47, seq=4381, ack=1
china(http) → cam(54190) HTTP/1.1 200 OK (text/html) ……
cam(54190) → china(http) [RST] TTL=64, seq=25, ack zeroed
china(http) → cam(54190) ……其余页面内容
cam(54190) → china(http) [RST] TTL=64, seq=25, ack zeroed
china(http) → cam(54190) [RST] TTL=47, seq=2921, ack=25
开头三个复位报文序列号对应了GET报文的序列号+1460和+4380(3 × 1460)。[23]我们认为防火墙发出三个不同的值是想确保发送者接受复位,即使发送者已经从目的地收到了“全长”(1460字节)ACK报文。复位报文的序列号需要“正确”设定,因为现在多数TCP/IP实现都会严格检查序列号是否落入预期窗口。[24](这个验证序列号的内在漏洞由Watson在2004年首先提出。[25]
此结果还显示,在连接被打断后仍然收到了从中国机发来的一部分页面。然后剑桥机响应了那两个意外报文,发送了自己的TCP复位。注意它将确认号置零而没有使用随机初始值的相关值。收到的所有复位报文的TTL[26]都 是47,而中国机来的报文的TTL都是39,说明它们来源不同。如果来源的初始值都是64,这也许说明复位产生的地方距离服务器有8跳(hop)。 traceroute显示那是通信从Sprint网络(AS1239)进入中国网通集团网络(AS9929)后的第二台路由器。
我们也从中国服务器的视角看这次连接封锁:
cam(54190) → china(http) [SYN] TTL=42
china(http) → cam(54190) [SYN, ACK]
cam(54190) → china(http) [ACK] TTL=42
cam(54190) → china(http) GET /?falun HTTP/1.0
china(http) → cam(54190) HTTP/1.1 200 OK (text/html) ……
china(http) → cam(54190) ……其余页面内容
cam(54190) → china(http) [RST] TTL=61, seq=25, ack=1
cam(54190) → china(http) [RST] TTL=61, seq=1485, ack=1
cam(54190) → china(http) [RST] TTL=61, seq=4405, ack=1
cam(54190) → china(http) [RST] TTL=61, seq=25, ack=1
cam(54190) → china(http) [RST] TTL=61, seq=25, ack=2921
cam(54190) → china(http) [RST] TTL=42, seq=25, ack zeroed
cam(54190) → china(http) [RST] TTL=42, seq=25, ack zeroed
我们可以看到,当检测到“坏”报文,防火墙也向中国机发送复位(“[RST]”)报文,但都在GET报文(以及其响应报文)后面。最后两个复位报文(零确认号)是剑桥机发送的。
其他到中国机的复位(因为有“falun”而生成的)TTL都是61,这意味着它们在3跳以外生成,初始值为64。这跟剑桥观测到的8跳偏移不一 样。不过这说明可能有不止一台设备在生成复位──或者初始值经过调整不是64。我们目前对于观测到的这种不对称性没有确定的解释。
开始三个复位的序列号也设置在一定范围(+25,+1485,+4405)以确保命中,事实上+25报文就已经重置了连接。[27]第四、五个复位报文检查确认号发现,它们可以视作连接重置前中国机成功发送的两个报文的响应。

3.2 直接重置连接

防火墙不仅检测内容,还有其他封锁规则。我们发现,只要进行一次“坏”连接,在短时间内相同两主机之间的所有网络通信在经过检查之前就都被封锁了。前面也是连接被封搜,不过现在开始继发连接也会被封锁了。比如,在上面一例以后立刻继续,我们看到:
cam(54191) → china(http) [SYN]
china(http) → cam(54191) [SYN, ACK] TTL=41
cam(54191) → china(http) [ACK]
china(http) → cam(54191) [RST] TTL=49, seq=1
复位报文从防火墙而 来(也往服务器而去)随之客户端便关闭了连接。如果客户端在复位到达前成功发送GET报文,便会接着收到多个防火墙发来的复位(即使GET报文是完全无毒 的)。接下来便是从服务端来的复位──服务器收到复位后便会立刻在GET到达前关闭连接。由于GET发来时不再存在打开的连接,服务端便按照协议返回一个 复位。值得注意的是,防火墙在SYN阶段(三次握手阶段一)没有试图重置连接,而是等到了SYN/ACK(阶段二)。虽然可以在客户端一发出SYN就给它 复位报文,但只有等到SYN/ACK才能构造出对服务端起作用的有效复位。[28]
在实验中我们发现,节点被阻断通信的时间是可变的。有时候是几分钟,有时候可能是一小时。平均时间大概在20分钟,不过由于观测到时间值有在特定值附近聚集的显著趋势,我们怀疑不同的防火墙组件有不同的时间延迟设定;这就需要深入理解是到底是谁在处理通信,才能较准确地预测封锁周期。

3.3 其他中国网络的情况

我们获取了中国自治系统(AS)的一个列表,并从中生成了在全球路由表中所有中国子网的列表。[29]然 后我们利用了一个修改过的tcptraceroute,判断出通信是通过哪个AS从国际网络进入中国,并从中得知了中国主干边际网络的实体。结果便是: AS4134,AS4837,AS7497,AS9800,AS9808,AS9929,AS17622,AS24301和AS24489。然后我们在各 个AS中挑选了样例服务器测试,发现所有网络都有都跟前面描述相似的复位行为(除了AS24489:跨欧亚信息网)。以此我们可以推出:我们的结果正展示 了典型的“防火长城”系统。情况在2006年5月下旬是这样的,但并不一定普遍适用。[30]

4 防火长城的设计

基于以上实验结果,以及中国使用的技术设备类型的描述──比如思科的“安全入侵检测系统[31]──我们提出以下模型来描述中国防火墙中路由器的工作方式(此模型很符合观测,但仍是推论性的,因为中国的网络提供商没有发布关于这些系统的任何技术规格):
当报文到达路由便被立刻放入适当的向前传输队列。此报文也被送到带外IDS设备进行内容检测。如果IDS(关键词匹配)认为此报文“不好”,那么便为连接两端各生成三个TCP复位报文(有三个不同的序列号)交由路由器传输。[32]
IDS在逻辑上是与路由器分离的,很难从路由传输队列中去除或者延迟“坏”报文。然而发出复位关闭连接是相对简单的。如果路由器相对繁忙,而IDS 工作正常,复位报文会在“坏”报文之前发送;这也是我们在实验中观测到的主要情况,虽然有时候复位报文会拖在后面。复位报文的设定值充分显示出,设计者担 心与路由器相比IDS的拥塞导致“坏”报文跑在复位报文前面。这种设计中如果不发送附加的复位,在繁忙情况下防火墙是无法保证封锁的可靠性的。
一旦IDS检测到需要封锁的行为,它也可以向主路由器添加一条简单的丢弃规则而不发出复位。[33]我们相当怀疑这种做法在主干高速路由器上扩展性差,而在IDS内的封锁简单而廉价。
我们还观测封锁的时长得知,提供防火墙功 能的设备不止一个。我们进行了进一步实验,发送256个包含威胁性字串的报文通过防火墙,虽然是从一个机器上发出的,但将它们的源地址设置分别为256个 连续的IP地址值,即中国防火墙会认为这是256个不同机器在发送需要封锁的内容。结果是,我们观测到有时候返回的复位报文是乱序的。然而现代互联网处理 报文基本上是用FIFO(先进先出)队列,[34]那 么对于这种失序的最简单解释便是,不同的报文给了不同的IDS,它们各有各的FIFO队列但在发送复位时负载不一样。可惜我们发现这个实验引起了很多的报 文丢失(不是所有的连接都返回了应有的复位报文),不能对报文失序程度有直观感受。这样我们也没法(通过队列建模)确定平行IDS设备的数量下界。我们计 划以后再做这个实验。

4.1 防火墙“状态”

没有证据证明带外IDS设备互相通信,并共享网络连接“状态”的记录。实验表明在一个边际网络触发防火墙不影响通过其他边际网络的通信。
而在“状态”本来应该保留的地方(IDS设备中)却没有关于TCP状 态的检查。设备孤立地检查报文,于是将?falun分散到相邻两个报文就足以避免检测。更有甚者,这些设备对于是否有连接存在也不关注,我们的许多测试中 甚至没有进行三次握手打开连接就直接发送GET报文。事实上除了初始检测之后的持续封锁,没有证据证明IDS设备做了其他什么特别的事情,IDS只是一次 检查一个报文而已。

5 有意忽略复位

防火墙完全依赖于终端节点以标准兼容方式实现TCP协议[35],在收到复位报文时中断连接。如上所述,虽然有时候防火墙有点超常,复位报文跑在GET报文前面结果被仔细验证一番以后丢掉了,不过在下一个报文到达防火墙的时候连接就会被防火墙摧毁所以,总得来说还是没有什么区别。
不过现在考虑如果终端节点不遵守标准然后TCP复位被彻底忽略的情况,我们会想到,即使触发了IDS,防火墙也对HTTP传输没有任何影响。于是我们进行了深入实验两边的终端节点都忽略TCP复位的情况。这有许多方法可以实现,我们选择设置合适的报文过滤防火墙规则。在Linux可以安装iptables并使用此命令:
iptables -A INPUT -p tcp --tcp-flags RST RST -j DROP
来丢弃传入的RST置位报文。如果是FreeBSD的ipfw那么命令是这样的:
ipfw add 1000 drop tcp from any to me tcpflags rst in
当双方都丢弃TCP复位时我们发现网页传输确实没有被封锁。在剑桥端检测传输的结果:
cam(55817) → china(http) [SYN]
china(http) → cam(55817) [SYN, ACK] TTL=41
cam(55817) → china(http) [ACK]
cam(55817) → china(http) GET /?falun HTTP/1.0
china(http) → cam(55817) [RST] TTL=49, seq=1
china(http) → cam(55817) [RST] TTL=49, seq=1
china(http) → cam(55817) [RST] TTL=49, seq=1
china(http) → cam(55817) HTTP/1.1 200 OK (text/html) ……
china(http) → cam(55817) ……其余页面内容
cam(55817) → china(http) [ACK] seq=25, ack=2921
china(http) → cam(55817) ……其余页面内容
china(http) → cam(55817) [RST] TTL=49, seq=1461
china(http) → cam(55817) [RST] TTL=49, seq=2921
china(http) → cam(55817) [RST] TTL=49, seq=4381
cam(55817) → china(http) [ACK] seq=25, ack=4381
china(http) → cam(55817) [RST] TTL=49, seq=2921
china(http) → cam(55817) ……其余页面内容
china(http) → cam(55817) ……其余页面内容
cam(55817) → china(http) [ACK] seq=25, ack=7301
china(http) → cam(55817) [RST] TTL=49, seq=5841
china(http) → cam(55817) [RST] TTL=49, seq=7301
china(http) → cam(55817) [RST] TTL=49, seq=4381
china(http) → cam(55817) ……其余页面内容
china(http) → cam(55817) [RST] TTL=49, seq=8761
……接下来这个页面就完整了。
网页以正常方式传输,除了中间夹杂一些防火墙的TCP复位报文。由于被完全忽略(一共28个复位),它们对客户端的TCP/IP栈没有任何影响。客户端仍然继续接收网页,正常发送ACK。中国端也能看到类似的正常传输夹杂复位的情形。
这样,只是简单地忽略防火长城发出的报文我们就让它完全失效了!这无疑会让它的实现者大为恼火。

5.1 迷惑封锁

一方面是在连接建立以后通过发出TCP复位来阻断继发连接,另一方面我们也观察到一些防火墙有 时还有附加策略。在一些节点(当然是随机的),我们看见了防火墙发来的伪SYN/ACK报文。显然其序列号是随机而且无效的。如果防火墙的SYN/ACK 报文比真报文先到那么连接失效──客户端从伪SYN/ACK中获取了随机的序列号并发给服务端错误的ACK,于是服务端便返回复位报文,导致客户端关闭连 接。实际上,如果客户端发送GET比较快,还会收到一批其他报文,导致防火墙和服务端的进一步复位:
cam(38104) → china(http) [SYN]
china(http) → cam(38104) [SYN, ACK] TTL=105
cam(38104) → china(http) [ACK]
cam(38104) → china(http) GET / HTTP/1.0
china(http) → cam(38104) [RST] TTL=45, seq=1
china(http) → cam(38104) [RST] TTL=45, seq=1
china(http) → cam(38104) [SYN, ACK] TTL=37
cam(38104) → china(http) [RST] TTL=64, seq=1
china(http) → cam(38104) [RST] TTL=49, seq=1
china(http) → cam(38104) [RST] TTL=45, seq=3770952438
china(http) → cam(38104) [RST] TTL=45, seq=1
china(http) → cam(38104) [RST] TTL=45, seq=1
china(http) → cam(38104) [RST] TTL=37, seq=1
china(http) → cam(38104) [RST] TTL=37, seq=1
对付这种防火墙的 新策略比处理伪复位报文麻烦许多。因为即使客户端忽略了服务端来的(完全真实的)复位,还是会继续错误理解服务端的序列号,导致不能与服务端同步以完成三 次握手打开连接。当然如果有时候防火墙的伪SYN/ACK跑在真报文后面,就会被客户端忽略不造成任何混淆,不过防火墙仍然会坚持不懈用复位报文来打断连 接但是由于复位报文都被忽略了所以也没有用,网页照样显示。
重要的是确定来的两个SYN/ACK报文谁是真的。在样例中我们觉得它们很好区分,防火墙版的TTL值大不相同,没有DF标志,没有TCP选项。这些伪SYN/ACK在现在为止还是像伪复位一样很好过滤的,防火长城再次失效。另外,由于只有封锁继发连接时才会使用这种策略,那么客户端可以把服务端的TTL记下来,而防火墙是搞不清该往伪报文里填什么值的。
不过,防火墙越 搞越复杂,说不定就能造出没法区分的SYN/ACK报文来了。那客户端直接把第一个收到的SYN/ACK当成防火墙发出的伪报文即可。不过要是防火墙又来 时不时来延时一下才发送伪SYN/ACK(让思维简单的机器通过,打倒思维复杂的机器!)那么这场复杂的“博弈”会升级成更深奥的战略对决。要注意打开网 页常常会有多个连接,那么防火墙即使只是搞掉其中一部分也会觉得有“胜利感”。
一个高效的客户端策略(先决条件是客户端和服务端都丢弃复位报文)是将所有传入SYN/ACK报文视为有效(防火墙以后也许会发好几个过来),然后检查全部的序列号和确认号直到从服务端收到一个ACK以确认正确的取值。不过这对于像iptables或者ipfw这种简单的报文过滤系统来说太复杂了,超出实现能力。
新一轮“博弈”也许是防火墙开 始针对所有客户端报文伪造ACK。可能客户端可以通过检测从服务端获得的真正RST来看穿防火墙的整个伪连接,于是防火墙连这些都要开始伪造了──这样下 去策略变得不知道有多复杂。不过终端节点确实有优势来最终判断报文是来自(有状态的)对方还是(无状态的)防火墙。要是防火墙也开始记录“状态”,那么整 个主要架构的变化(虽然一定又是一笔巨大的开支)便会带来许多其他可用策略,优势也会决定性地偏向防火墙这边。
可是必须注意到,防火墙的SYN/ACK 报文伪造问题不能通过改变服务端的TCP/IP栈来安全地解决。那样的话服务端需要发现客户端持续地响应的那个“错误”的ACK值并改变自身状态以响应这 个从伪SYN/ACK报文中出来的值。但这样就去掉了一个Bellovin记录的重要安全步骤,进而导致恶意主机伪造源IP地址访问的漏洞。[36]
另外,在可以“嗅探”并伪造报文的对手面前进行安全连接,这在密钥交换协议邻域已经得到充分研究。未决的问题是,如何利用中国防火墙目前的架构性缺陷,通过对现有TCP/IP栈的简单修改来战胜防火长城。

6 拒绝服务攻击

我们前面提到,单个包含?falun之类内容的TCP报文就足以触发节点间至多长达一个小时的封锁。如果伪造源地址,就可以发起(但也是受限的)拒绝服务(Denial of Service)攻击,阻断特定节点间的通信。不过不同的人有不同的目标,这对某些攻击者来说已经足够。比如,识别并阻止地区政府机构的主机访问“Windows自动更新”;或者阻止某个部委访问一个联合国网站;或者阻止中国海外使馆访问家乡网站。
我们计算发现,即使是一个人通过单个拨号连接也可以发起相当有效的DoS攻击。这样一个人每秒可以产生大约100个触发性报文,假设封锁时间大约是20分钟,那么120000对节点便可被永久封锁。当然,现在的DoS攻击几乎不会通过单个拨号方式实现,而是在快得多的网络上以巨大的数量进行。那么120000便可以乘到你满意。不过防火墙的IDS组件也许没有资源记录如此大量的封锁连接,所以实际的影响要考虑受到此类资源限制的情况。还要注意当IDS处理DoS攻击的时候它处理其他连接信息的资源就会变少,于是其效用也就暂时降低。

6.1 DoS攻击的限制

进一步实验显示此防火墙的封锁方式比我们迄今为止解释的还要复杂一些;因此DoS攻击的效果不一定有刚才那样说得那么好。
首先,封锁只应用于相似端口上的继发连接。[37]只 有端口值前9最高有效位与触发封锁的端口对应时,防火墙才会封锁这一连接,这样的端口每次有128个。Windows这类系统会连续分配临时端口,于是平 均有64个继发连接会被封锁。(有时比如触发封锁的端口是4095那么就不会有继发封锁)反之OpenBSD之类的系统会随机分配临时端口,于是继发连接 被封锁的可能性只有1/500。
我们对防火墙的这种行为没有确定的解释。不看端口直接封锁所有连接似乎还简单有效许多。[38]这么做也许是为了避免误封NAT后面的其他用户,或者是用来确定发送某报文的IDS。也许这么做只是有意要显得神秘而愈发有威慑力。然而从DoS攻击者的角度,除非有特殊条件可以预测临时端口,要让所有可能端口段都被封锁所需的报文发送量便增长了500倍。
图1:中国防火墙对“坏”字符串的封锁情况。
图1:中国防火墙对“坏”字符串的封锁情况。
2006年二月上旬我们进行了一次10天的试验,每小时一次从256个相邻IP地址进行连接。这里是前128的结果;其余部分模式也十分相似。黑点表明连接被封锁,白点表明没有封锁,灰点是结果不定(完全没有响应)。在110小时前后可见防火墙策略的显著变化(封锁更多的IP地址)。
其次,并非所有IP地址的流量都被检测过。我们每小时进行一次突发连接,发送一组256个IP地址连续的含有“?falun”的报文。起初每组报文 只有约三分之二被封锁掉,封掉的地址每次不同。不过几天之后几乎所有报文被封锁。我们无法通过逆向工程确定地址选择的算法,不过IP地址选择确有鲜明的模 式[39],暗示背后的机制可能相当简单。最直接的解释是资源匮乏──流量的三分之二也许就是整个系统可以处理的极限。显然某些时候如果一部分机器没有进行报文检测的工作,DoS攻击也就不可能通过它们发起。
最终需要注意的就是,这些实验只是在中国内外的少量节点上进行的,虽然我们得到了足够一致的结果,但像“防火长城”这种复杂的系统我们还是可能忽略了它的某些重要特性。因此虽然我们认为DoS攻击可以在许多情况下成功,我们也不能保证任一节点对上的任一次攻击都能成功。

7 战略考虑

要让流量顺利通过中国防火墙就 必须要求双方忽略复位。“世界其他地方”的机器如果想在中国也能正常访问,只需稍作调整。但在中国这边的人就不那么愿意装一些特殊软件了。主要问题是防火 墙可能做的,不仅是封锁,还有记录。随之而来的可能就是侦查,安装的特殊软件便会被查获,有人便会对你安装此种软件的动机产生某种看法。
中国防火墙的 报文检查功能也可以通过加密的方法规避。如果当局通过对内容的统计分析检测出加密通信,那么安装特殊软件遭到侦查的问题还是一样的。由于加密系统一般会话 结束后便废弃密钥,通信内容是色情还是政治演讲这是无法分辨的。如果用丢弃复位的方法穿墙,防火墙可以通过日志的方法记录封锁触发内容,当局便可以检查日 志并对这两种通信采取不同措施。这两种方法相比有人觉得丢弃复位法更有优势。
如果复位丢弃广泛以毫不相关的理由应用,中国政府可能不得不对复位丢弃软件采取更加容忍的态度。
关于软件防火墙的一些研究指出如果例行丢弃TCP复位会产生一些副作用。[40]复位报文主要是用来快速报告不受欢迎的传入连接。如果远端机工作良好,那么忽略报文而不响应复位只会产生稍微多一点的流量。
然而,对于不想丢掉所有的TCP复位的人来说,当然这里也有另一种策略。[41]目前TTL校验就是一种检测复位报文真伪的简单方法。特别地,我们注意到Watson提出的通过第三方伪复位造成连接关闭的复位攻击[42],通常的防御手段是仔细验证序列号。如果再加上复位报文的TTL校验,就可以更好地识别伪复位。本文作者之一编写了一段20行的FreeBDS补丁[43],可以丢弃TTL值严重偏离的复位报文。到现在用户体验都很好。其他操作系统和个人防火墙大概也不会觉得添加这个功能很麻烦。
当然,中国防火墙也可以改进,让前面提及的规避方法难以实现。特别是它可以较容易地构造正确TTL的复位报文发往触发报文的相同方向。不过要想获得相反方向的正确TTL就不大容易了,因为网络路由基本上是非对称的,防火墙不能透视通信的两个方向。更复杂的方法是将报文从路由队列中移除(或者延迟到内容检测完成才放行)。除非报文在抵达终点前被阻止,我们的基本策略──无视防火墙发出的噪音──将继续有效。
另一套完全不同的防火墙策略则是当封禁被触发后不向该站点转发任何报文。不过我们前面提到此法扩展性极差,因为完成这个“内联”过程需要路由器间的快速通路──而且,全面的封锁无疑增加了DoS攻击的威力。

7.1 打破“防火长城”的公共政策动力

特别是在美国,有相当的政治利益关心着中国之外的公司如何帮助中国政府压制信息、锁定持不同政见者和异见网志作者。特别地,在2006年2月的一次国会听证会上,相当数量的美国大型公司由于其政策和行为而受到了严厉谴责。[44]不过对于如何绕开中国的过滤技术现在也有更多的关注。比如由CIA部分资助的SafeWeb,在2000到2003年运营了一个匿名网络代理,同时它还开发出一种昵称TriangleBoy的反审查技术。[45]2006下半年发起的加拿大的Psiphon计划旨在让“不受审查国家的公民向在他们防火墙背后的朋友和家人提供自由的网络连接”。[46]
可以预测本文所描述的通过忽略复位报文规避中国防火墙的 方法也会引起相当的兴趣。当然也会有“军备竞赛”的危险,所以双方采取的策略可能复杂得多。让防火墙立刻失效方法也是相当直接的;不过实现这个方案需要中 国外的服务器和中国内的浏览器同时丢弃复位。服务器一方显然会有动力去实现复位丢弃,因为这样就让在中国的人可以访问。不过要是看看中国国内的情形和人们 改变浏览器(或者操作系统)配置的动力就会知道事情远比这复杂得多。虽然都是运行在中国的机器上,这些软件却都是在中国以外开发,特别是大多数软件都安装 在微软开发的Windows上。
我们这里提出一个关于公共政策的问题:是否应该鼓励或者强制微软修改程序以帮助规避中国防火墙?显然对于中国的审查有着广泛谴责,那么反审查措施当然会得到政治意见和公共意见的赞同。[47]在本节前面我们提到,对这种改进的技术性反对意见是很有限的,这种改进可以提升对第三方攻击(防火墙只是第三方干涉网络通信的特例)的防御安全性。然而微软(以及其他操作系统和浏览器开发商)很可能不愿意冒犯中国政府,那么在被强制之前他们会一直拖下去。
一般的常识便是软件容易修改,硬件不易修改。不过把硬件改动的时间与制订新法规的时间相比就会知道,在强制供应商提供规避防火墙功能的法律生效之前,中国政府就会采用新的封锁硬件。[48]可以推测,新的硬件会考虑到我们提到的问题并对复位丢弃免疫。因此我们认为通过立法(强制供应商)并不是实用的办法,除非立法是普遍意义上的、不关注技术细节的。让供应商少去讨好中国政府多关心其他所有人,这才是最现实的道路。

8 结论

本文我们展示了基于报文内容检测的“防火长城”。当过滤规则触发时,伪复位报文便发向TCP连接两方。然而真正的报文亦完好通过防火墙,于是通过忽略这些复位,通信便不受干扰。相同方向上的继发连接也被封锁(只有在端口相关的情况下),不过通过忽略复位通信仍可以顺畅继续。
以上结果对于中国当局具有相当的意义,他们也许会加强他们的系统、修补防火墙的漏洞。当然我们在前面也说,这并不容易。[49]然而对于希望自由访问网络的中国居民来说,以上结果意义就小得多,因为他们的活动仍然受到记录和监视。只有当丢弃复位报文成为普遍做法以后,人们的才能说他们是无意中翻墙的。这种想法也不能算离谱,因为验证TCP复位是否为伪造也是TCP/IP栈应该做的。
我们还展示了封锁的副作用:为DoS攻击提供了可能性。当然这种DoS攻击只能用在特定节点之间。利用一套封锁机制来封锁什么东西这本身并没什么新意,但如果防火墙不作足够的状态记录,我们也看不到避免这种攻击的简便方法。
我们展示的结果也关系到其他使用类似复位机制来保护自身利益的国家、机构、企业。他们应该谨慎地认识到这种封锁完全依赖于被封锁者的默许。一些相对中国来说的小国家会经受更大的DoS攻击风险,因为他们的终端节点要少得多,防火墙在攻击效果变得显著之前尚不会过载。

9 补记

2007年春另外一组研究者(Jedidiah R. Crandall和其他人的“ConceptDoppler”项目)[50]的一些实验也揭露了这个防火墙的工作细节,但复位机制是基本不变的。不过他们的测量表明复位现在开始发生在中国互联网的内部,不仅是边际路由器;且与我们一年前观察到的相比封锁在繁忙时段变得更加断断续续。他们的研究手段也让他们可以发表一份关于被过滤话题的统计列表。

注释

  • [1] OpenNet Initiative, “Internet Filtering in China in 2004–2005: A Country Study,” OpenNet Initiative, http://www.opennetinitiative.net/studies/china/ONI_China_Country_Study.pdf (accessed October 21, 2007).
  • [2] OpenNet Initiative, “Probing Chinese Search Engine Filtering,” OpenNet Initiative: Bulletin 005, http://www.opennetinitiative.net/bulletins/005/ (accessed October 15, 2007).
  • [3] Ronald J. Deibert and others, eds., Access Denied: The Practice and Policy of Global Internet Filtering (Cambridge: MIT Press, 2007).
  • [4] Nart Villeneuve, “Censorship is in the Router,” June 3, 2005, http://ice.citizenlab.org/?p=113 (accessed October 15, 2007).
  • [5] OpenNet Initiative, “Probing Chinese Search Engine Filtering.”
  • [6] RST标志置位的TCP报文。这种报文表明一方要求立即关闭当前连接不再传输。
  • [7] See Maximillian Dornseif, “Government Mandated Blocking of Foreign Web Content,” Security, E-Learning, E-Services: Proceedings of the 17 DFN-Arbeitstagung über Kommunikationsnetze, eds. Jan van Knop, Wilhelm Haverkamp, Eike Jessen, 617–646 (Dusseldorf, Germany: GI, 2004).
  • [8] Richard Clayton, “Failures in a Hybrid Content Blocking System,” in Privacy Enhancing Technologies: 5th International Workshop Cavtat, Croatia, May 30-June 1, 2005 (Berlin, Germany: Springer, 2006): 78–92.
  • [9] Richard Clayton, “Anonymity and Traceability in Cyberspace,” Technical Report (2005), http://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-653.pdf (for details of the complexity, see the extensive discussion in “Anonymity and Traceability in Cyberspace”) (accessed October 15, 2007).
  • [10] Benjamin Edelman, “Web Sites Sharing IP Addresses: Prevalence and Significance,” Berkman Center for Internet & Society, http://cyber.law.harvard.edu/people/edelman/ip-sharing (accessed October 15, 2007).
  • [11] Dornseif, “Government Mandated Blocking,” 626–27.
  • [12] Center for Democracy & Technology v. Pappert, 337 F. Supp. 2d 606 (E.D. Penn. 2004).
  • [13] King Abdulaziz City for Science and Technology: Local Content Filtering Procedure. Internet Services Unit (2004), http://www.isu.net.sa/saudi-internet/contenet-filtring/filtring-mechanism.htm (accessed October 15, 2007).
  • [14] OpenNet Initiative, “Internet Filtering in Burma in 2005: A Country Study,” OpenNet Initiative, http://www.opennetinitiative.net/burma/ONI_Burma_Country_Study.pdf (accessed October 15, 2007).
  • [15] Telenor, “Telenor and KRIPOS Introduce Internet Child Pornography Filter,” press release, September 21, 2004, http://presse.telenor.no/PR/200409/961319_5.html (accessed October 15, 2007).
  • [16] Dornseif, “Government Mandated Blocking,” 642-44; Clayton, “Failures in a Hybrid Content Blocking System,” 78–92.
  • [17] IDS可以将多种不规则的表现转化为标准形式,然后与封锁列表比对作出正确决策。
  • [18] 这种对称必须存在,因为防火墙需要同时封禁网络请求和回应。
  • [19] Villeneuve, “Censorship is in the Router.”
  • [20] SYN(同步)标志标明了打开TCP连接时的第一个报文。
  • [21] 这是对SYN报文的回应,其SYN和ACK(确认)置位,用“SYN/ACK”来表示在TCP连接打开过程中的第二个报文。
  • [22] 关于TCP的准确细节,和发起连接时交换SYN、SYN/ACK和ACK置位报文的方法原因,可以查阅很多好的网络通信教材,比如W. Richard Stevens, TCP/IP Illustrated, Volume 1, The Protocols (Reading, MA: Addison-Wesley, 1994)。
  • [23] 当我们启用TCP时间戳且报文包含12字节TCP附加选项的时候,这个值变成1448的倍数。
  • [24] TCP对所有数据报文用序列号进行标记,指示报文包含数据的顺序。当报文丢失、延迟或重复时,可以靠序列号来重建数据流。“窗口”是指在没有收到确认时最 多可以发送的数据量。现在的互联网中,检查序列号落入窗口(复位报文序列号符合预期)是避免第三方干扰连接的重要安全措施。
  • [25] Paul A. Watson, “Slipping in the Window: TCP Reset Attacks,” Open Source Vulnerability Database, http://osvdb.org/reference/SlippingInTheWindow_v1.0.doc (accessed October 15, 2007).
  • [26] 存活时间(TTL)初始值由报文发送者确定,通过一个路由就减一。这是为了确保报文不在路由间无穷循环,当TTL为零时报文就被丢弃了。于是通过校验TTL值可以推算报文走过的距离。
  • [27] 如果复位在GET报文之前到达,则此复位报文不会被接受。服务器是FreeBSD系统,在连接的这个阶段,TCP栈接受的复位的序列号必须精确匹配上次发送的确认的值,以防止拒绝服务攻击。在GET报文到达前其值为+1,于是这时所有的复位都是无效的。
  • [28] SYN/ACK报文含有连接双方选定的序列号。
  • [29] AS指特定ISP拥有的骨干网络。我们采用的是CERNET的“China ASN List”,http://bgpview.6test.edu.cn/bgp- view/cur_ana/ipv4cn/china_asnlist.shtml。互联网路由器保存有优化路径列表,而“全球路由表”表达了特定AS对 地址的所有权。
  • [30] See Jedidiah R. Crandall and others, “ConceptDoppler: A Weather Tracker for Internet Censorship” (14th ACM Conference on Computer and Communications Security, Alexandria, VA, October 29–November 2, 2007) http://www.cs.unm.edu/~crandall/concept_doppler_ccs07.pdf (accessed October 15, 2007).
  • [31] Earl Carter, Secure Intrusion Detection Systems (Indianapolis: Cisco Press, 2001).
  • [32] 即,检测报文内容的设备是在实际连接“旁边的”于是只能检测“坏”流量而不能对其有任何直接影响。
  • [33] 路由器一般都有根据特定标准进行报文过滤的功能。
  • [34] Yi Wang, Guohan Lu, and Xing Li, “A Study of Internet Packet Reordering,” Information Networking (Heidelberg, Germany: Springer-Berlin, 2004): 350–359.
  • [35] J. Postel, ed., “Transmission Control Protocol, DARPA Internet Program Protocol Specification” (memo, Network Working Group Request for Comments, September 1981) http://www.ietf.org/rfc/rfc793.txt (accessed October 21, 2007).
  • [36] S. Bellovin, memorandum, May 1996, in Network Working Group Request for Comments, “Defending Against Sequence Number Attacks,” http://www.ietf.org/rfc/rfc1948.txt (accessed October 15, 2007).
  • [37] ──译注,此节所述似已过时。在翻译完成的时候译者测试发现,继发封锁跟初始端口或者继发端口没有关系,所有端口的继发连接都被屏蔽。
  • [38] HTTP通信不仅在80端口(tcp/http)上被封锁,还有其他一些端口也受到影响。不过一个端口被封不影响其他邻近端口,比如80端口被封不影响433端口(tcp/https)。
  • [39] 见图1。
  • [40] See Clayton, “Anonymity and Traceability,” 81.
  • [41] 未来中国的防火墙还可能通过FIN报文来打断连接,然而忽略所有FIN报文则会导致不能正常连接,到那时TTL校验法会更好。
  • [42] Watson, “Slipping in the Window.”
  • [43] Robert N. M. Watson, “Patches Associated with My Academic Research,” http://www.cl.cam.ac.uk/~rnw24/patches (accessed October 15, 2007).
  • [44] Suzanne Goldenberg, “Congress Accuses Google of Collusion,” The Guardian, February 16, 2006, http://www.guardian.co.uk/china/story/0,,1710616,00.html (accessed October 15, 2007).
  • [45] SafeWeb, “TriangleBoy Whitepaper,” SafeWeb, 2003, http://web.archive.org/web/20030417171335/http://www.safeweb.com/tboy_whitepaper.html (accessed October 15, 2007).
  • [46] Psiphon, http://psiphon.civisec.org (accessed October 15, 2007).
  • [47] Stokely Baksh, “US Calls for Fall of Great Firewall,” United Press International, February 15, 2006; Kate Allen, “Today, Our Chance to Fight a New Hi-Tech Tyranny,” Observer, May 28, 2006; Cory Doctorow, “See No Evil?,” Guardian, July 6, 2007.opinion. 47
  • [48] “此法案是近年来孕育期最长的。导致此法案产生的斯科特报告是在五年半前的1996年2月发表的。保守党政府接受了此报告的提议并立即发出了资讯文书。工 人党1997年的宣言坚定承诺要采取行动。于是1998年出了那本白皮书。不过之后政府就不闻不问于是,过了三年此法案才推出。”Hansard Parliamentary Debates, Commons, 6th ser., vol. 374 (2001), col. 457.
  • [49] 本文中描述的实验都是在2006年春进行的,本文的初始版发表在2006年6月的隐私增强技术研讨会上。
  • [50] ──译注:见http://www.conceptdoppler.org/。

忙了就容易出错……出错了就容易脑残

最近忙啊……虽然是假期……但是还是要做项目,这几天要进行初期的验收测试,忙啊……
本来以为在家工作效率比在学校好,但是这要分情况啊……正赶上这几天家里天天来好多人……唉……白天吵吵的,还经常被叫去干着干那……晚上已经累得要死,根本没精力碰电脑了……
话说忙了就容易出错,而且还经常出很脑残的错误:

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (obj instanceof GuetCommandPacket) {
            return false;
        }
        final GuetCommandPacket other = (GuetCommandPacket) obj;
        if (this.command != other.command) {
            return false;
        }
        if (this.targetAddress != other.targetAddress && (this.targetAddress == null || !this.targetAddress.equals(other.targetAddress))) {
            return false;
        }
        if (this.maskAddress != other.maskAddress && (this.maskAddress == null || !this.maskAddress.equals(other.maskAddress))) {
            return false;
        }
        return true;
    }

就这段代码困扰了好久,最后跟踪才发现……第二个if那里少了一个!,这函数永远不会返回true吧……
话说这段代码的原型是NB生成的,我也就改了第二个if,原文是:

        if (getClass() != obj.getClass()) {
            return false;
        }
不过这样不能处理继承关系,所以改掉了。
最后再吐槽一句:Blogger也脑残了,为啥?看图。

2008年8月14日星期四

换到Windows Server 2008了

经过3次重装,终于把win2008装上了。除了没有激活以外,目前感觉一切还好。

感觉2008还是挺不错的系统的,适合用来搞开发的。速度上比Vista要快,又具备了Vista的华丽界面。因为是实验性质的……这个系统不会用很长时间(因为没激活啊……)所以就装了一个32位的,兼容性之类的比较好。

之所以重装了3遍,是有原因的。第一遍装Datacenter版的……装完以后第一件事就是进入用户管理,吧默认的管理员禁用,然后新建了一个用户,注销管理员,用新建立的用户登录,装软件,然后傻眼……忘了吧这个用户设为管理员了……泪……
那安装官盘进入恢复控制台,吧SAM文件恢复……然后开始装驱动……感觉不怎么好(有心理阴影了么= =)装到一半蓝屏,一气之下格调重装。
第二遍装好驱动以后,在故障恢复控制台吧Program Files转移到了D盘(就是使用mklink命令,建立硬链接,Vista以后的系统有这玩意真不错,要不以前我都是吧ProgramFiles 挂载分区的)
然后开始装应用软件,装到一半想打开Wlan支持和Aero效果,结果系统提示:无法把文件转移到另一分区。估计是program files的问题。恢复目录,继续装,然后重启……然后再重启……然后又重启= =||然后格调在装一遍……。
第三遍时迷迷糊糊的选了标准版系统……一切正常(没有动program files)。打开了windows audio 和themes服务(还有一个windows audio ****的服务也要打开,2003没有这个)换上Aero效果(2008没有了系统分级)然后用Vista优化大师打开了任务栏透明,更换profile路径,更换了登录背景,但是没有效果,估计是logonui.exe结构不同……无视这点。打开组策略,关闭关机事件跟踪,关闭登录的Ctrl-alt-del.然后开始装各种软件……还好都下有x32和x64两个版本。
Google拼音个google桌面终于又能有了,喜(上一个vista64不能用,奇怪,上上个又能用)
恢复firefox,发行需要重装一次FF才能注册默认浏览器。
然后装上office2007,打开自动更新……发现不像vista没有了MUI语言包……ma,算了,反正很少用。

2008年8月10日星期日

【FWD】奥运会开幕式 你绝不知道的内幕

1.主题曲《you and me》中文名是《油和米》,表示对08年石油和粮食问题的关注。

2.点火仪式,一开始李宁跑出画卷,表现了古代中国走在世界前列;后来越来越慢,表现了近代中国落后于东西方列强;最后点燃火炬,表现了同归于尽的伟大构想。







3.这幅用人组成的CPU图形 象征着国产IT业蒸蒸日上,伴随整齐的人形方阵与随后而来的冷色系演出 表达出国产CPU不但运行准确 而且散热功能一流。

4.对于部分演出 在开幕式之前就有了一些网友爆料。例如这就是某网友在2个月前提供的。
奥运开幕式方案暴光
张艺谋导演的奥运会开幕式方案爆光:在鸟巢中央摆上四万张麻将桌,十六万人在热血沸腾的民乐中尽情狂搓,在音乐高潮处嘎然而止,然后齐声狂喊:“胡!”此刻总书记在主席台闪亮登场,宣布本届奥运会正式开幕!

但由于NBS事件 导演不得不将节目排序和内容稍微做了些许修改。一些古人出场,代表着麻将起源于古中国,这和5000年博大精深的中华文化是密不可分的。

然后演员先后分为四组,东西南北。而麻将在中间伴随着演员得动作上下起伏 开始洗牌。随着麻坛开始翻云覆雨,展开了旷世之战。这时候突然间。。。。




东面主席台位置的 东道主中国 - 做出了龙牌 庄家门清 无混 清一色 一条龙。



自摸! 和牌! 中国赢了 大家都傻眼了。

中华上下五千年
自摸和牌在眼前

随着时间的推移,虽然文字经过历史的淘汰与演变,但麻将始终作为中华的国粹保存了下来。再一次证明了中华文化的伟大。暗示着西 南 北方列强 在世界得麻将桌上 注定失败的结局。东道主中国将会是未来的赢家!自摸没混庄提龙 不是你们想屁和就屁的!

Google会检测访问者是不是自动的?

今天一位在德国的朋友跟我说,他被Google封锁了……听说过GFW封锁Google,还没听过Google主动封锁的。
他收到的是这样的信息:
您提到的 CAPTCHA 页是 Google 为应对在 Google.cn 上的点击量急速上升的情况而采取的措施。 CAPTCHA 图片可以帮助我们确定点击量是来自自动漫游器软件还是来自具体用户。 请注意,您的网络收到此页面的原因是我们的系统检测到来自您的网络 IP 地址的自动查询。

向 Google 发送任何类型的自动查询均属违反服务条款的行为。 有关针对个人用途的 Google 服务条款的详情,请访问 http://www.google.com/terms_of_service.html 。 请注意,"发送自动查询"包括但不限于以下情况:

* 使用任何向 Google 发送查询的软件来确定网站或网页在 Google 各类查询中的排名。
* 对 Google 进行"元搜索"
* 在 Google 上执行"离线"搜索。

您网络中很有可能有用户因运行上述程序之一而导致违反服务条款。 在您找到此用户并且删除所涉及的程序后,系统会自动取消对您的 IP 地址的封锁。

对于您可能遇到的任何不便,我们深表歉意,并希望能够尽快恢复您在 Google.cn 上的搜索。
好像是由于什么东西在不断的向google提交请求造成的,我让他更换了IP地址,清空Cookies都无效,我很奇怪Google是怎么做到的?为了测试,我用Java写了一个小东西不断提交请求,结果我还是可以继续搜索(我在几分钟内提交了500多次请求)。
总之,这是一件很神奇的事情,值得继续调查- -

2008年8月7日星期四

我的数据包满世界跑

天知道是为什么……围着世界绕了一圈

C:\Users\Bearice>tracert ipv6.google.cn

通过最多 30 个跃点跟踪
到 ipv6cn.l.google.com [2401:3800:c001::68] 的路由:

1 <1 毫秒 * <1 毫秒 bearice-ibm [2002:780c:419b:4:2e0:4cff:fe11:a1f3]
2 427 ms 449 ms 440 ms 2001:9b0:65::2
3 440 ms 430 ms 449 ms 2001:9b0:1:1::2
4 448 ms 449 ms 448 ms 1670-bahnhof.cr0-r84.kn1-sto.se.ip6.p80.net [2001:16d8:aaaa:1::1]
5 478 ms 449 ms 470 ms v1317-r84.cr0-r73.gbl-mlm.se.ip6.p80.net [2001:16d8:1:1317::73]
6 460 ms 450 ms 449 ms v1306-r73.cr0-r72.gbl-cph.dk.ip6.p80.net [2001:16d8:1:1306::72]
7 449 ms 449 ms 466 ms v1308-r72.cr0-r70.tc2-ams.nl.ip6.p80.net [2001:16d8:1:1308::70]
8 445 ms 469 ms 460 ms ams-ix.he.net [2001:7f8:1::a500:6939:1]
9 459 ms 489 ms 459 ms 10gigabitethernet1-4.core1.lon1.he.net [2001:470:0:3f::1]
10 449 ms 449 ms 429 ms 10gigabitethernet2-3.core1.nyc4.he.net [2001:470:0:3e::1]
11 429 ms 449 ms 450 ms 10gigabitethernet1-2.core1.nyc1.he.net [2001:470:0:37::2]
12 429 ms 449 ms 439 ms 2001:458:26:2::280
13 * 482 ms * v6-laIX01.kddnet.ad.jp [2001:268:ff00::8]
14 * * 619 ms v6-oteCORE02.kddnet.ad.jp [2001:268:ff00::2]
15 498 ms 499 ms 479 ms 2001:200:0:fe00::1dec:0
16 478 ms 499 ms 489 ms tpr5-ge0-0-0-7.jp.apan.net [2001:200:901:7::5]
17 620 ms 599 ms 610 ms 2001:200:901:5774::1
18 * 644 ms * 2001:200:901:5774::1
19 * 656 ms * 2001:468:ff:516::1
20 657 ms 680 ms 680 ms 2001:468:ff:516::1
21 588 ms 670 ms 670 ms kreonet-1-lo-jmb-706.sttlwa.pacificwave.net [2001:504:b:10::6]
22 569 ms 580 ms 560 ms 2001:320:1b00:1::1
23 689 ms 700 ms 700 ms 2001:252:0:2::301
24 699 ms 710 ms 690 ms 2401:3800::1:38
25 688 ms 740 ms 690 ms 2401:3800::1:43
26 699 ms 710 ms 690 ms 2401:3800::1:43
27 688 ms 709 ms 720 ms 2401:3800:c001::68

跟踪完成。

C:\Users\Bearice>

Back to work

今天停电一整天,闲着没事在家吧两台电脑都拆开来清理了一遍。清理本本的时候吓了一跳,风扇上积累的灰尘厚厚的……怪不得前些天跑Everest的压力测试时,CUP温度达到100摄氏度……后来想想,灰尘可能是从PC卡接口处进去的,PC卡接口就在出风口旁边,我又正好把那个防尘盖弄丢了(因为实在是太松了),看来以后要经常清洗了。
下午出去逛了一下……基本上干什么都要查身份证,这OG当口,ZF就会干这些没用的事情,除了给人们出行带来严重的不方便,起不到任何作用(因为就算没拿身份证,也是可以进去的,我试过好几次了)。而且就算真的有KB分子,你查身份证有个毛用,难道身份证上标明了“此人是KB分子”么……
昨天下午开始就折腾着重装系统(来个个小毛孩把系统弄坏了……),算下来有好久没有写代码了,上次的Spring的问题还没有解决……烦啊……
PS:一天没上线……留言邮件又是一大堆啊……