有关DSR的网络拓扑结构和实现方法

前两天在delphij老大的blog中看到了一篇《使用DSR模式实现单IP服务冗余》,觉得很有意思,因为这个实现方式与我以往所见到的有些不同,通过关闭ARP响应来解决虚拟IP在负载均衡设备和服务器上可能冲突的问题。随即提问了一下我所熟悉方式的实现是否可行,勤恳的delphij竟然又写了一篇来解释这个问题。不过这篇的思路似乎与我原来的想法有点出入,所以仔细又思考了一下,最终决定还是要完整的阐述一下我的思路。

我虽然见过一些DSR的实现方式,然而只不过是阅读架构文档而已,想当然来的东西跟最后实际实施出来的东西肯定有差距,所以把自己认为的设计思路记录下来,看看最终是否可行。

首先是拓扑图:

介绍一下简单的信息:

Public VLAN直连Internet,LB和Router分别有一个网卡接口连在这里,用于承载Internet的虚拟IP自然也就是绑在LB连在Public VLAN的NIC上了,方便起见,随便起个IP: 202.96.100.100(202.96段是中国电信骨干IP段,很多坏事都是这里发生的:D)
Internal VLAN是放服务器集群的网段,当然就用私有地址,就用典型的192.168.1.0/24吧,这里的Server使用IP 192.168.1.101

首先从数据流角度来看(红色箭头上的标号):

客户发起到请求: 61.152.X.X:1025 –> 202.96.100.100:80
负载均衡设备通过匹配包,发现目的IP为虚拟IP,根据Load balance算法挑选一台Server,将数据报直接路由到这台Server,不做任何修改(减TTL不算)61.152.X.X:1025 –> 202.96.100.100:80
Server看到数据报的目的IP是虚拟IP,并发现虚拟IP绑定在自己的lo上,认为目的地是自己,OS派发到应用层Web Server处理Request并生成结果,结果数据包变为 202.96.100.100:80 –> 61.152.X.X:1025
数据报发往路由器,路由器看到目的地为客户IP,路由到Internet去。

这个过程与传统NAT方式的Load Balance的区别在于,LB不修改目的地址,直接将数据报通过路由的方式转发给服务器集群。然而这里的难点就在于:如果不修改目的IP,那必须让Server能够对发往虚拟IP的请求做出响应,那就必须要把虚拟IP绑定在Server端,因此虚拟IP就同时出现在了两个地方:LB和Server,解决这个冲突就是完成DSR的关键所在。对于此点引用delphij的原话:

实现DSR结构的关键是,通往Internet路由器的那个网络上,只有负载平衡设备在网络上宣示虚拟出来的那个IP的MAC地址,这样,当请求进来的时候,数据会发到负载平衡设备,而不是某一台服务器上。

Delphij采用的方法是,将服务器上网卡的ARP功能关闭,这样服务器虽然绑定了虚拟IP,但不会对外界对于虚拟IP的MAC地址解析请求做出响应,所以完美解决了IP重复的问题。缺点是ARP一关Server自己会找不到Router或者网络内的其他服务器,因此需要手工维护一个静态ARP表。

而我所采用的方式,是不将虚拟IP绑定在实际网卡上,只是绑定在Server的还回(lo)上,这样依旧可以起到缩减ARP响应域的作用。

Delphij认为这样会需要一个额外的Public IP,不过我认为如果Server放在私有地址VLAN的话,应该是不需要额外的IP,在如图的这种拓扑中应该可以完美的工作。只要LB和Server中作出如下配置(红色罗马数字):

I.  Load Balancer要特别设置的地方有:

需要有合适的负载均衡算法以便于把流量分发给不同的Server。
对于TCP这种有状态的服务,需要使用较为宽松的状态机制来维持会话。

这里引用delphij的pf命令为例,如下,round-robin是负载均衡算法,keep-state(slopppy)是宽松状态匹配,这一点对于DSR也是尤为重要,因为DSR的特点就是从Server发回的响应不经过LB,LB看不见回去的响应包,所以Session track必须能容忍这种半吊子连接。而且这里似乎也必须修改Session的timeout时间,否则会有问题,这里无关者略过:

FreeBSD pf规则举例:pass in on em0 route-to { em1 内网IP1, em1 内网IP2, em1 内网IP3 } round-robin proto tcp from any to 公网IP port http keep state (sloppy)

II.  Server端需要的设置:

在lo上绑定虚拟IP 202.96.100.100,这样Server才会认为目的地是自己。
Web Server本身要使用虚拟IP作为监听IP,比如Apache配置Virtualhost的话这样用:<VirtualHost 202.96.100.100:80> ,如此以来Web server会对到虚拟IP的请求做出响应,且响应的源地址也是虚拟IP而不是自己网卡上的私有IP。
Server将默认网关设置为Router的IP,这样对于请求的响应就会发往Router而不会返回LB了。

III. Router上应该不需要什么特殊设置,知道把发往Internet的包路由出去就行

这样整个DSR就应该能走通了,不过这个玩法我也只是想出来而已,还没有经过实践,当初看到过F5的nPath实现,应该就是这么种玩法,不过估计实际应用时应该会有我这里没有想到得地方,所以有时间的话,最好还是找几个设备搭一下看看吧,先把设想架构放这儿,改天回来验证。说实话,delphij指出这里必须要有一个额外的公网IP才能保证知道出去的包怎么走,我这点还是没有想通。不管怎样,写出来让大家指正吧,至少在写这篇的过程中,我已经将自己以前没考虑到得一些细节补充完整了,对于自己来说,也算是不小的收获。

TCP/IP协议栈DoS漏洞

在本月的周二补丁日,微软发布了一组补丁用于修复存在于TCP/IP协议栈上的漏洞。可以从http://www.microsoft.com/technet/security/bulletin/MS09-048.mspx看到微软的更新声明。

同时,Cisco也发布了用于解决存在于IOS同样漏洞的补丁,声明于此http://www.cisco.com/warp/public/707/cisco-sa-20090908-tcp24.shtml

发布补丁其实并没什么稀奇的,特地为这个漏洞/补丁写一篇Blog的原因是这个漏洞背后有点非常有意思的八卦:

这个漏洞能造成的影响其实相当巨大,当初问题被发现时,非常多的TCP/IP协议栈实现都被证明是存在问题的。而在接下来的一段时间内,发现这个问题的几个人开发了一个攻击工具,经证明可以对Windows/Linux/BSD等等的机器发起攻击,仅仅需要发起数kbps的流量,持续几分钟之后就会导致目标服务器完全停止响应。
可被攻击的目标非常广泛,任何有端口在监听的服务器、PC甚至路由器都会被攻击。
实际这个问题属于协议的设计缺陷,所以当发现者公布这个问题时,他们没有使用漏洞(Vulnerability)这个词,而是使用了瑕疵(Flaw)。
厂商们对此问题的反应是承认此瑕疵存在,但因为对其修补需要反复的研究论证后才可能实现,因此拖了相当久的时间。Linux似乎挺早就做了相应的修补措施,但MS和Cisco却花了一年多直到今天才真正去修复这个瑕疵。以至于发现者其一还没有熬到这个问题修复就已经驾鹤西去。

其实这个问题的原理并不是很复杂,它起源于针对SYN Flood的解决方案SYN Cookie,对于SYN Flood/SYN Cookie不了解的人可以先补补课,这里有篇不错的文章:http://www.ibm.com/developerworks/cn/linux/l-syncookie/index.html

简单说,SYN Flood是因为攻击者发送虚假的SYN包而本身不做其他任何多余的工作,而被攻击者在接收到SYN后需要进行一系列建立Session、分配内存等资源分配的操作,导致攻击者可以用极小的代价耗尽被攻击者的所有资源,从而达到DoS(Denial of Service)的效果。而SYN Cookie则使服务器在接到SYN后并不立即进行资源分配,而是将SourceIP:SourcePort – DestinationIP:DestinationPort的4元组通过某稍微复杂但又不怎么消耗资源的算法转换得到一个值放入SYN/ACK的ISN中发送出去(称作Cookie)。此时真正的客户会响应这个SYN/ACK并在发回的ACK再次包含这个Cookie,服务器通过验证Cookie和四元组是否对应来判断客户是否合法后,才进行资源的分配工作。伪造SYN的攻击者因为无法收到或者猜出Cookie,无法完成三次握手,也就达成不了DoS的效果了。

而这个TCP/IP协议栈的瑕疵的思路是将SYN Cookie的思路用于攻击,客户端本身不消耗资源,也不维护连接状态,通过在发送的包中加入Cookie来辨识服务器,通过构建特定包使服务器完成三次握手,完成后服务器必然开始分配连接所需要的资源,例如维持连接状态表,分配内存,定时器。在此之后攻击者发送0窗口的ACK通知服务器这一端没有足够的buffer来传输数据,这样服务器就会持续维持此连接,并分配定时器定时来探测攻击者的窗口是否打开。此时攻击者所要做的只是间隔一定时间内继续发送0窗口包告诉服务器继续维持连接,但攻击者本身仍机不需要消耗任何资源。反复此过程多次,服务器中将会有多个持续的连接,虽无数据传输,但服务器本身需要维持这些链接,并还需要不时触发定时器来探测窗口,导致服务器的协议栈资源被大大消耗,到达一定程度后,服务器会因为资源耗尽而停止响应。

问题的发现者撰写了很详细的资料用于描述这个问题,我将个人认为非常不错的一个PPT放到Google Docs上供大家研究,Sockstress是作者开发出来验证这个漏洞可以被利用造成DoS的工具:

作者的主页上还有更多的资料可供研究:http://sockstress.com/

目前这个漏洞在这一年内究竟有多少真正实现DoS的案例还没有统计资料,个人认为应该有不少实际被攻击成功的例子,但只是没有广泛引起关注而已。

对于此问题的修复,MS和Cisco都没有披露补丁的原理,个人猜测是加强对于恶意空置连接的检测,并强制对端如果持续0窗口一段时间后强行关闭连接并释放资源。因为协议RFC本身并未对此作出强制或建议规定,各厂商的协议栈实现可能会有所不同。就像SYN Cookie当初的情况一样,实现本身对RFC的要求有所相违背,但为了保护协议栈本身却不得不做出此类抉择,估计这也是厂商拖了这么久才真正放出补丁的原因之一吧。不知以后的RFC中是否对比会有所补充。

说了这么多东西,其实我个人并不是对这个漏洞的实现细节特别感兴趣,只是刚好最近这个事儿比较热门,而我工作上上维护的某个Service的程序设计行为与这个漏洞的原理有非常大的共通之处。程序本身的行为对协议栈造成了很大的压力,刚好最近流量突增,使得部分服务器过载而开始间歇性罢工,一帮兄弟们在焦头烂额的想办法修,所以实在是想对这个漏洞吐个槽。程序本身的行为设计时就没考虑周全,流量增加到Server撑不住才想办法修,对于运营人员来说,实在不是什么令人爽得起来的事,

最后附送一个SLashdot上对这个事儿讨论的链接:http://it.slashdot.org/story/09/09/08/1839258/Microsoft-Cisco-Finally-Patch-TCP-DoS-Flaw,其实这个站上的人们也挺有娱乐精神的,吵着吵着就跑题,甚至连Windows NT最早某些工具用了BSD协议代码的那些旧八卦也挖出来了。无聊时看看还真提神-_-

网生异象,必有妖孽出世

今天晚上发现了一个极其诡异的现象,以前从大陆到海外的访问,只要一出大陆路由节点,必定平添180-200ms的延迟,然而今天却出现了这样的现象:

从中国到北美竟然只有80ms的延迟, 这是从来没有的状况。谁说海底光缆一定会带来100ms以上的延迟的?这就是铁证,立存此照!

猜想:这两天网络极其不稳定,再加上政府部门的一些动作,怀疑骨干网上某神秘设备在开始新一轮进化,目前只是抽抽疯。

Update: 次日一切如常,果然只是抽抽疯。

Blog访问速度优化

抽了点时间把Blog动了点小手脚,加了点东西减了点东西改了点东西,现在速度应该有一个非常显著的提升,如果有感觉到变快的麻烦吱个声。

目前改动还是实验性的,没形成什么系统理论,只不过是一些已知的空间换时间的技巧的排列组合而已,等慢慢总结下心得来的时候好好写一写。

弱智的上海移通

公司的网络一直是走得移动的企业宽带,貌似是光纤到楼的吧。3个月前去申请从2M扩容到10M。对方很早就说做好了,但是从我本地网关出口的流量监控来一直都没突破过2M。

昨天下午,网络突然不通了,于是报修。半小时后来了个扛着笔记本的技术员,把本子往出口网线处一接,ping了下对端,不通,然后就说了句去对端机房看看,就跑了。

然后就是持续到今天上午的网络瘫痪,移通的说法在换了n个版本后,网络还是依旧不通。

一上午没办法干活不行,于是再把出口接上自己看看能不能查到线索,于是发现了如下tcpdump结果:

09:55:00.006472 00:00:00:22:25:8c > ff:ff:ff:ff:ff:ff, ethertype ARP (0×0806), length 42: arp who-has 211.X.X.33 tell 211.X.X.34
09:55:01.003376 00:00:00:22:25:8c > ff:ff:ff:ff:ff:ff, ethertype ARP (0×0806), length 42: arp who-has 211.X.X.33 tell 211.X.X.34
09:55:01.763189 00:0b:be:51:b9:00 > ff:ff:ff:ff:ff:ff, ethertype 802.1Q (0×8100), length 64: vlan 209, p 0, ethertype ARP, arp who-has 211.X.X.34 tell 211.X.X.33
09:55:01.791808 00:0b:46:2b:e2:82 > 01:00:0c:cc:cc:cd, ethertype 802.1Q (0×8100), length 68: vlan [...]

有一点专业精神好不好?!

最近频频出现一些媒体报道失实的问题,并且有越来越泛滥的趋势,甚至这些媒体本身都成为假报道的制造者。近几个月内就发生了北京某报纸纸包子事件,以及央视死人变活事件。这两家一家是知名的平面媒体,一家是全中国最NB的电视媒体。难道说这代表整个中国的传统媒体已经没有任何公信力了吗?!

还好我们还有网络,我们还坚信网络不能隐藏任何真相。然而不乐观的是,现在新兴的网络媒体也在渐渐地学会这种风气,可谓为了流量不惜“造”出任何新闻。这些类似狗仔队的行为出现在娱乐新闻内也罢,然而对于最需要严谨的技术范畴内的新闻,现在也越来越娱乐化了。

比较以下两则新闻,一则为国内某知名IT资讯网站编译出来的,一则是国外某知名IT资讯网站写出来的。

Sun宣称:Open Solaris将成为Linux杀手

Sun宣布,Open Solaris将成为Linux的有力对手,并且在不远的将来将Linux淘汰出局.
Solaris系列业务的副经理Marc Hamilton宣称他们将发布开源的Solaris系统对抗目前的Linux.
Sun将在明年年初公布一个”印第安纳”工程,(它吸收了Linux社区的精华理念),Solaris在某些方面比现有的Linux系统要优秀,Sun寄希望于一些优势来与Linux发行版本一决高下.
Sun还宣称这款系统以后”将和Java一样普及”.

Sun Says OpenSolaris Will Challenge Linux“Sun Microsystems has ambitious plans for the commercial and open source versions of its Solaris operating system. The company hopes to achieve for Solaris the kind of widespread uptake already enjoyed by Java. This means challenging Linux. ‘There’s an enormous momentum building behind Solaris,’ according to Ian [...]