记一次lvs-tunnel模式的故障分析(7)

一、测试环境

 
类型 IP
负载均衡器 eth0:10.20.73.20
VIP eth0:0 10.20.73.29
后端真实机 10.0.0.7(web01)、10.0.0.9(web02)
 

二、异常现象

在client上ping VIP是通的,但是访问服务的时候却发现不通。

 

DR上所有连接都为SYN_RECE状态。(类似TCP SYN Flood。)

三、故障排除思路

1、抓包
从RS上抓包的情况来看,也和ipvsadm列出来的结果是一样的,服务器收到客户端发过来的S标记的包后再也没了下文。在DR上抓包,也是同样的效果。
 
2、分析
1.说明客户端发的包确实到了DR,并且DR也已经把包发送给了后端RS,问题应该出现在RS上。
此时的数据流分析如下:
客户端发送S标记的包过来,服务端发送ACK确认后,就老老实实在在等待客户端发送ACK过来后,就可以愉快的工作了,但是万万没想到的是,此时服务端的ACK包被无情的过滤了,客户端不可能发ACK过来,所以就一直停留在SYN_RECE状态了。
 
3、解决过程
1.抓包,只能看到结果,但是还不知道具体导致RS不回应Client的原因;
2、关闭防火墙、关闭selinux,reboot,问题依旧,没得到解决;
3、以为是没有开启路由转发导致,所以就echo "1" > /proc/sys/net/ipv4/ip_forward,打开RS的路由转发功能。
4.上面三板斧过后,还是不见效,于是就开始找度娘了,先是网上搜了一大把关于怎么配置lvs tunnel的文章,先看看是不是我配置有误,经过查看和对比,没有问题。问题还是没有得到解决。
5.当天晚上,没睡好觉,第二天一早就起来,继续排查和搜资料,可能是tunnel模式在现实中使用的比较少,所以网上关于tunnel提问的人也不是很多。看来这个问题只能自己摸索了。
 
于是先从tunnel模式的数据流着手,
【CIP->VIP】:客户端访问调度器上的VIP
【DIP->RIP|CIP->VIP】:DR经过IPIP协议将IP包进行二次包装,其实就是把包头进行特殊封装,把上次的包头作为数据包装了进去。
【VIP->CIP】:RIP收到包后,进行包头解析,发现是从DIP发过来的,但是因为RS上是经过IPIP协议进行解包的,所以他看到的真实源IP为VIP,目标IP为CIP,而此时,源IP恰巧就在RS上,嘿嘿,这里不是恰巧,是特意设置的,而且把他的嘴给封了,arp广播被禁用,这样,他就不会喊人了,把自己就当成了源IP了,所以此时RS就直接回应CIP了。
上面说了一大推理论,看来也没有解决问题,但是从上面的整个数据流来看,比较清晰明了,问题就出在RS发包上。但是为什么RS会丢包呢?思考了好久,反复模拟发包过程,突然想起了之前涛哥(网络老师)说的一句话,"数据在网络上是双向的,我们要最好确保他来回一致,如果来回路线不一致的话,就可能有去无回了,此时需要我们给他指定回来的路"。这个场景正好是路由来回不一致的场景,但是我已经指定了回来的路由/sbin/route add -host $VIP dev tunl0,那为什么还不行呢?是不是linux系统本身也会有限制呢?于是就把思维转向了sysctl中的那些内核参数,度娘一上,发现还真有个反向路径过滤参数rp_filter,这个参数也没有错,他正是为了干掉哪些DDOS攻击里面的TCP SYN Flood。而我们此时的场景正好符合他的要求,所以被无情的过滤了。具体请参考:http://en.wikipedia.org/wiki/Reverse_path_filtering
大概意思如下:
 设置参数为0           非源检测,即对源不进行检测。注意:如果这里不检测的话,对于洪泛攻击可能立马就瘫痪了。
设置参数为2            严格模式,进来的每一个包都进行检测,如果接口上不是最佳回包,数据库包将会检测失败。默认情况下,失败的的包会丢掉。
设置参数为2           松散模式,每个进来的包将会进行检测,如果源地址通过本机任何接口都不可达的话,数据包将会失败。
 
rp_filter - INTEGER(参数为整数)
        0 - No source validation.   
        1 - Strict mode as defined in RFC3704 Strict Reverse Path
            Each incoming packet is tested against the FIB and if the interface
            is not the best reverse path the packet check will fail.
            By default failed packets are discarded.
        2 - Loose mode as defined in RFC3704 Loose Reverse Path
            Each incoming packet's source address is also tested against the FIB
            and if the source address is not reachable via any interface
            the packet check will fail.
 
        Current recommended practice in RFC3704 is to enable strict mode
        to prevent IP spoofing from DDos attacks. If using asymmetric routing
        or other complicated routing, then loose mode is recommended.
 
        The max value from conf/{all,interface}/rp_filter is used
        when doing source validation on the {interface}.
 
        Default value is 0. Note that some distributions enable it
        in startup scripts.
Red Hat are (correctly) setting rp_filter to 1, strict mode.  In this case a packet coming in eth0 will have its source address routed out on the same interface that it came in on (because that's the default route).  However, a packet coming in on eth1 will have it source address routed out on a different interface to the one it came in on and it will be discarded.  Silently.
 
This is basically asymmetric routing and is quite possibly not what you want anyway (it messes up TCP flow control) so there are two ways to fix this: stick with asymmetric routing and permit it or fix the asymmetric routing.
 
The first one is easiest: in /etc/sysctl.conf change rp_filter=1 to rp_filter=2).  You'll need to load that and restart the network.  It's probably easiest to reboot :-) to be sure.  I suspect that it was not restarting enough things that prevented this change from working before.
 
The second one may be simple as simple as adding those routes that should go out on eth1 to the routing table or running some routing daemon.  It depends on your network topology, basically. This would be the preferred solution if it's practicable.
 
注释:解决方法,1是关闭反向路径过滤功能;2是添加一条满足反向路径过滤的路由。
由于linux系统处于自身保护考虑,这个参数默认设置成1,:严格模式。
二话不说,我先把参数给调了,看看效果,于是在tunnel模式里面加了一行:
echo "0" >/proc/sys/net/ipv4/conf/tunl0/rp_filter
重启服务:
service ipvstunl stop
service ipvstunl start
 
测试:OK,正常了。

 

posted @ 2017-09-10 10:06  skyflask  阅读(982)  评论(0编辑  收藏