深入理解GFW:内部结构 - mj5219054/clash_for_windows_pkg GitHub Wiki

对GFW进行了大量的黑箱测试,尽管大多数实验数据都得到了良好的解释,但是还是有些数据或者体现出的规律性(不规律性)没有得到合理的解释。比如TCP连接的各项超时时间,比如Google的443端口被无状态阻断时,继发状态的持续跟源IP相关的问题。比如一般TCP连接的继发阻断时,窗口尺寸和TTL的连续变化特性。这些问题已经超出纯协议的范畴,需要对GFW的内部结构进行进一步了解才能明白其原因。所以在这一章介绍GFW的实现和内部结构。 总的来说,GFW是一个建立在高性能计算集群上规模庞大的分布式入侵检测系统。其分布式架构带来了很高的可伸缩性,对骨干网一点上庞大流量的处理问题被成功转换成购买超级计算机堆砌处理能力的问题。它目前有能力对全部国际网络流量进行复杂和深度的检测,而且处理能力“还有很大潜力”。

图片

  • 对于GFW在网络上的位置,有很模糊的认知:“在三个国际出口作旁路监听”。然而还希望对在出国之前最后一跳之前发生了什么有详细了解。

GFW希望对不同线路的链路异构性进行耦合,并研究了快速以太网、低速WAN、光纤、专用信号多种类型链路的耦合技术。而根据《国际通信出入口局管理办法》,几大ISP有自己的国际出入口局,最后在公用国际光缆处汇合,比如在海缆登陆站之前汇合。据已有的资料,安管中心(CNNISC)有独立的交换中心,而且有报道说各个ISP是分别接入其交换中心。这样几个材料就可以形成一致的解释:为了适应不同ISP不同的链路规格,GFW自己的交换中心需要对不同的链路进行整合,不同的ISP分别引出旁路接入GFW。而没有接入GFW的线路则被称为“防外线”[来源不可靠],不受GFW影响。接入的线路类型应该主要是光纤线路,因此通常称此接入方式为分光。这就是“旁路分光”。另外实验发现,GFW的接入地点并不一定紧靠最后一跳,因此图中以虚线表示。需要注意GFW的响应流量重新接回网络的地点难以确认,这里只是假设是与接出的地点相同。 负载平衡

  • 面对多条骨干监测线路接入产生的巨大不均匀流量,不能直接接到处理集群,而是要先进行汇聚然后再负载均衡分流成均匀的小流量,分别送给处理集群并行处理。首先需要将网络设备通信接口(Pos、ATM、E1等)转换成节点可用的主机通信接口(FE、GE等)。处理负载均衡的算法经过仔细考虑,希望实现:流量均匀分布、对于有连接协议保持连接约束、算法简单。连接约束是指:一对地址端口对之间的一个连接全部通信都要保证调度到同一个节点。

GFW关于负载平衡的文章中主要提出两种算法。

  • 一种是轮转调度,对于TCP,当SYN到达时,以最近分配的节点号取模再加1,并将连接存入hash表,当后继流量到达时就能查询hash表获得目标节点号。[03a]另一种是基于连接参数的散列,对于N个输出端口调度输出端口号是H(源地址, 目标地址, 源端口, 目标端口) mod N,这个H函数可以是xor。

而之前的某个实验中我们碰到一种特殊的模式,负载平衡在解释其现象中起到了重要作用,下面专门分出一节详细说明。

  • 实验步骤:发送含有关键词的特制包通过GFW,并接收GFW返回的阻断响应包。因为触发阻断之后,同地址对和同目标端口的连接都会受到继发阻断,为了消除这种干扰,一般采取顺序改变目标端口的扫描式方法。通过前期一些实验,我们已经发现和确认某类(二型)阻断响应包中的TTL和id都跟窗口大小有线性关系,我们认为窗口是基本量(二型窗口为5042时id发生了溢出,只有在id根据窗口算出时才会发生此种情况)。 然而在顺序扫描中有一种特殊的模式无法用现有证据解释。进一步的实验步骤是:在源、目标地址不变的情况下,顺序扫描目标端口,记录返回的阻断响应包的窗口。数据如下图,横轴是时间(秒),纵轴是端口号,每个点代表一次阻断触发事件中观测者收到的阻断包的窗口值。

图片

  • 可以明显看出一种线性增加的趋势。图像取局部放大看:

图片 为什么有独立可区分的不同的线?这些线表示了什么?为什么有13根?为什么每根线是递增的?

为什么有独立可区分的不同的线?现象具有明显的可以继续划分的子模式,而不是一个整体的随机量,并且每个子模式都有良好的连续增加的性质。因此可以推测产生此现象的内在机制不是一块铁板,而是多个独立的实体。进一步的实验事实是,如果顺序扫描端口每次增加13,那么只会产生一条较连续的线而排除其他的线。这直接证明了模13同余端口产生结果的不可分性、实体性,以及同余类间的独立性。

  • 这些线表示了什么?我们猜想,这13根线就表征了背后有13个独立实体分别根据某个内在的状态产生阻断响应,窗口值就是其内在状态的直接表现。 为什么有13个?而不是1个2个?这个时候,负载平衡就是对此事实的一种解释良好的模型。如果GFW有13个节点在线,由于希望将流量平均分配到每个节点,那么根据前面论文所述,便采用模的方式,在源、目标地址不变时,根据目标端口模13分配流量,目标端口模13同余的包会进入同一个节点。实际上更早的时候的一次实验是发现有15根线,同理可以猜测有15个节点在线。 为什么每根线是递增的?

  • 实验中发现,每次阻断GFW会分别向连接双方发送窗口值依次增加的两组阻断包,这样对于每方来说,每次阻断就会使窗口值增加2。每根线会递增正是说明节点在不断产生阻断包增加窗口值,一部分是实验观察者的观测行为触发的,另一部分则是普通网络流量造成的。如果对数据做差分并扣除观测造成的影响,甚至还可以对每节点产生阻断的速率有所估计。 但是为什么要让窗口递增?这背后的动机难以找到很合理的解释,可能这个窗口值有计数器的作用,也可能是为了在ip.id上对不同节点产生的包进行区分。事实上,一型的窗口值就是几乎随机但ip.id固定,窗口递增并非是必须的。 然而进一步的实验发现,如果目标端口、源地址不变,而目标地址顺序变化,图像就显得比较紊乱,找不出规律。虽然如此,仍然在局部可以识别出同时存在13根线的情况,进一步证实“13个节点在线”的猜测。这个实验的意义在于,通过对现象的分解约化,分离出GFW内部的某种独立实体结构,对论文中主张的负载平衡算法有进一步的实践证实,对GFW的内部结构得到进一步的认识。

  • TCP/IP栈将数据分片重组,流重组之后交给应用层解析。应用层由很多插件模块组成,耦合松,部署易。其应用层插件包括“HTTP、TELNET、FTP、SMTP、POP3、FREENET、IMAP、FREEGATE、TRIBOY”。

  • 有意思的是,这是首次官方确认GFW与Freegate、Freenet、Triboy的敌对关系。应用层的协议大家都很熟悉不用多解释,不过应用层问题比传输层更多了。好几个模块都有一些小毛病,比如某类HTTP模块只认得CRLF作为EOL,换作LF便呆了。再比如某类DNS模块,发的DNS干扰包,十有五六都校验和错误,查询AAAA也返回A,还不如关掉。多数模块都是得过且过,刚好可以工作,一点都不完善。这里列出的、发现的问题按照软件设计一般规律也只是冰山一角。由此推断,GFW的设计哲学是:better is worse。

  • 不过在可以生产论文的话题上,GFW绝不含糊,就是模式匹配。应用层模块把应用层协议解析好了,然后就要看是不是哪里有关键词,字符串匹配。搞了一堆论文出来,改进AC算法和BM算法,就差汇编的干活了,得出某种基于有限状态自动机的多模式匹配算法,特别适合GFW这种预定义关键词的需求。总之复杂度是线性的,攻击匹配算法消耗CPU什么的就不要想了。 响应机制的发展已经经历IP包过滤(静态IP包过滤、动态IP包过滤)、连接欺骗(传输层连接欺骗、应用层连接欺骗)两个阶段,并且形成了针对不同的应用多种方式共存的现状。 静态IP包过滤是IDS通过和被保护网络与外部网络之间的连通边的端点网络层设备(路由器、三层交换机等)进行联动,在其上设置访问控制列表(ACL)或静态路由表来实现对指定IP地址的过滤。

  • 由于需要过滤的IP地址数量很大,大多数的网络层设备上对ACL大小和性能的支持不能满足要求,因此,实际工作中大多采用静态路由的方式。使用该种方式,信息入侵检测系统只能通过专用客户端程序静态写入的方式进行访问控制,粒度大(IP地址级),响应时间慢,容量较小,但是可以静态写入路由设备的配置文件中,是非易失的。 动态IP包过滤是指入侵检测系统采用动态路由协议(BGP,OSPF等)和关键路由设备进行路由扩散,将需要过滤的IP地址扩散到路由设备中的路由表中,特点是响应时间快、容量大,但是只能动态地写入路由设备内存(RAM)中的路由表中,是易失的,同样粒度大。 连接欺骗指信息入侵检测系统在敏感连接传输过程中伪造连接结束信令(RST,FIN)发送给连接的源和目的地址,以中断该连接。特点是实时性强、粒度小(连接级),可以针对某一次敏感连接进行阻断。

  • 缺点是对分析系统工作状态依赖较强,需要向业务网上发送数据包,易受DoS攻击。 通过和连接级防火墙设备进行联动,可以针对连接五元组(传输协议类型、源地址、源端口、目的地址、目的端口)对数据流进行过滤。可以针对指定的任意五元以内的组合条件进行过滤,实时性强、粒度小 GFW有日志。这意味着什么?这就意味着当你翻墙的时候,你的所作所为都记录在案。不光是你一个人,其他所有人都经常翻墙。但据统计87.53%的人(361之316)都是无意之中翻墙,从统计理论上看,记录在案的无效信息过多会造成信息难以利用。因此GFW后期一直在做“数据融合、聚类、分类的研究”,鸭子硬上弓,各种神经网络、概率模型、人工智能的论文整了一大堆,效果如何呢?

GFW的日志应该会记录这样一些事件信息:

  • 起始时间、结束时间、源地址、目标地址、目标端口、服务类型、敏感类型。信息难以利用不等于不能利用,如果日志被翻出来了而且用户没有用代理,那么根据常识,从IP地址对应到人也只是时间问题。这就是说,GFW即使不能阻断,最差也是一个巨型监听设备。

  • GFW(北京)使用曙光4000L机群,操作系统Red Hat系列(从7.2到7.3到AS 4),周边软件见曙光4000L一般配置;GFW实验室(哈工大)使用曙光服务器],Red Hat系列;GFW(上海)使用Beowulf集群(攒的?)。

    GFW(北京)拥有16套曙光4000L,每套384节点,其中24个服务和数据库节点,360个计算节点。每套价格约两千万到三千万,占005工程经费的主要部分。有3套(将)用于虚拟计算环境实验床,计千余节点。13套用于骨干网络过滤。总计6144节点,12288CPU,12288GB内存,峰值计算速度48万亿次(定义不明,GFW不做浮点运算,2003年top500排名榜首地球模拟器5120个CPU)。
    

GFW的重要工作方式之一是在网络层的针对IP的封锁。事实上,GFW采用的是一种比传统的访问控制列表(Access Control List,ACL)高效得多的控制访问方式——路由扩散技术。分析这种新的技术之前先看看传统的技术,并介绍几个概念。

  • ACL可以工作在网络的二层(链路层)或是三层(网络层),以工作在三层的ACL为例,基本原理如下:想在某个路由器上用ACL控制(比如说是切断)对某个IP地址的访问,那么只要把这个IP地址通过配置加入到ACL中,并且针对这个IP地址规定一个控制动作,比如说最简单的丢弃。当有报文经过这个路由器的时候,在转发报文之前首先对ACL进行匹配,若这个报文的目的IP地址存在于ACL中,那么根据之前ACL中针对该IP地址定义的控制动作进行操作,比如丢弃掉这个报文。这样通过ACL就可以切断对于这个IP的访问。ACL同样也可以针对报文的源地址进行控制。如果ACL工作在二层的话,那么ACL控制的对象就从三层的IP地址变成二层的MAC地址。从ACL的工作原理可以看出来,ACL是在正常报文转发的流程中插入了一个匹配ACL的操作,这肯定会影响到报文转发的效率,如果需要控制的IP地址比较多,则ACL列表会更长,匹配ACL的时间也更长,那么报文的转发效率会更低,这对于一些骨干路由器来讲是不可忍受的。

而GFW的网络管控方法是利用了OSPF等路由协议的路由重分发(redistribution)功能,可以说是“歪用”了这个本来是正常的功能。 动态路由协议

  • 说路由重分发之前先简单介绍下动态路由协议。正常情况下路由器上各种路由协议如OSPF、IS-IS、BGP等,各自计算并维护自己的路由表,所有的协议生成的路由条目最终汇总到一个路由管理模块。对于某一个目的IP地址,各种路由协议都可以计算出一条路由。但是具体报文转发的时候使用哪个协议计算出来的路由,则由路由管理模块根据一定的算法和原则进行选择,最终选择出来一条路由,作为实际使用的路由条目。

  • AS(自治系统),AS内使用的都是OSPF协议,而AS之间的OSPF不能互通,那么两个AS之间的路由也就无法互通。为了让两个AS之间互通,那么要在两个AS之间运行一个域间路由协议BGP,通过配置,使得两个AS内由OSPF计算出来的路由,能通过BGP在两者之间重分发。BGP会把两个AS内部的路由互相通告给对方AS,两个AS就实现了路由互通。这种情况就是通过BGP协议重分发OSPF协议的路由条目。

  • 另外一种情况,管理员在某个路由器上配置了一条静态路由,但是这条静态路由只能在这台路由器上起作用。如果也想让它在其他的路由器上起作用,最笨的办法是在每个路由器上都手动配置一条静态路由,这很麻烦。更好的方式是让OSPF或是IS-IS等动态路由协议来重分发这条静态路由,这样通过动态路由协议就把这条静态路由重分发到了其他路由器上,省去了逐个路由器手工配置的麻烦。

  • 前面说了是“歪用”,正常的情况下静态路由是由管理员根据网络拓扑或是基于其他目的而给出的一条路由,这条路由最起码要是正确的,可以引导路由器把报文转发到正确的目的地。而GFW的路由扩散技术中使用的静态路由其实是一条错误的路由,而且是有意配置错误的。其目的就是为了把本来是发往某个IP地址的报文统统引导到一个“黑洞服务器”上,而不是把它们转发到正确目的地。这个黑洞服务器上可以什么也不做,这样报文就被无声无息地丢掉了。更多地,可以在服务器上对这些报文进行分析和统计,获取更多的信息,甚至可以做一个虚假的回应。