一直以来都尽量用开源思路解决问题, 我们部分办公网网关也是.
之前有写过怎么利用iptables禁止QQ号码登录问题, 时隔一年, 量有点大, 匹配的规则达到一千多条, 性能问题就开始突显了. 先给大家复习一下原创的怎么根据QQ号码进行登录管制方法.
string模块有个hex-string选项, 可以针对十六进制的数据进行处理, 我们只要找到QQ登录时候的”特征码”进行控制就可以了. 经过多个版本的多次抓包, 我们已经掌握了我们需要的特征码,(当时是用的tcpdump和smartsniff,之后发现wireshark已经提供了QQ协议)不过跟wireshark提供的特征码不一样, 不过能实现我们的需求即可. 没去多纠结了.下面是多个版本的特征码(少匹配长度测试有时候会出问题):
00020101000065 00010101000066 00010101000065 00010101000064
然后直接调用即可:
-i eth1 -m string –hex-string “|00020101000065|” –algo bm -j DROP
现在全部禁止登录了,要开白名单怎么办呢,我们只需要允许QQ号码的十六进制即可,很方便吧.
echo “obase=16;396162545″|bc | awk -F “” ‘{if(NF%2==”0″) {print $0} else {print “0”$0 }}’
用awk是因为十六进制的首位如果是0的话, 会自动省略, 我们需要自动加上.
#十六进制的QQ号码怎么转为十进制呢? 直接echo即可: echo $((16#179CF5F1))
得到QQ十六进制179CF5F1之后我们 -m string –hex-string |179CF5F1| –algo bm -j ACCEPT即可允许我的QQ登录了. 方便有效.
之后的之后,我们的规则开始庞大了, 问题来了, 很多人同时下载什么东西(有tc限速), 或者中午时候流量大的时候, 到网关的延迟就大了. 性能问题, 想办法.
第一个办法我们想到的是网卡中断问题,因为延迟大的时候, 繁忙的只是前面一两个cpu(top查看idle很偏,ksoftirqd进程也很单一), 因为都跑到第一二个cpu去了,单核利用,虽然单核利用会有些优势,比如缓存之类的,但是现在明显处理不过来了, 我们需要多核利用, irqbalance服务虽然是说可以智能调整,但是并不智能, 解决不了我们的问题, 不过我们可以自行调整. 先停掉irqbalance服务, 然后继续
处理步骤,我们先查看网卡(主要是内网网卡)的中断号: cat /proc/interrupts |grep em2,第一列就是中断号,先看下我们调整之后的效果吧:
这个是调整之后的状态,中间的数字代表第几个cpu处理的数据量,0代表没处理过,我们调整之前,后面全部是0,
我们实际上是调整网卡中断的cpu亲和力, 也就是/proc/irq/NUM/smp_affinity这个值, smp_affinity的值是十六进制表示,分别代表2的几次方,比如第3个cpu就是2的(3-1)次方, 我们直接echo进去即可. 问题来了, 我们要怎么调整呢?
有些网卡是通过cpu个数的网卡通道来解决cpu亲和力这个问题, 我们有8个cpu, 也就是上面看到的8个中断号的通道, 然后每个通道上面绑定一个cpu即可. 需要注意的是,我们这里不支持累加的写法,因为现在是多个通道表示方法,所以每个通道只能绑定一个cpu, 某些网卡是通过一个通道表示, 那种情况就是用累加表示. 否则如果用ff去代表所有cpu的话,网络会非常卡.
看下我们调整之后的结果:
cd /proc/irq
for i in `seq 68 75`; do echo -n “$i “; cat $i/smp_affinity; done
68 00000064
69 00000001
70 00000020
71 00000010
72 00000040
73 00000080
74 00000008
75 00000004
然后效果立即出来了, 看处理的数据量就开始变化了,关键的是延迟从200多ms直接降到1ms以下左右.top的每个cpu的idle时间都比较均衡了.
调整之后比较稳定了, 因为多个cpu在分担工作, 但是久了, 问题又出来了, 8个cpu都跑满负荷了. 这下得另外找方法了.
从iptables规则入手, 这里经过了一些衍变过程.
刚开始我们添加规则是比较随意, 之后多观察一下发现优化的空间比较大, 主要原则是什么呢, 让数据包尽快的通过, 尽量少匹配就可以了.
实现原则, 我们需要把一些无谓的流量先ACCEPT放行, 不要经过后面上千条的规则, 这样cpu的工作量少了很多.
QQ默认是用udp进行通讯, 当udp通讯异常时候才会进行tcp端口80 8080 443之类的进行连接, 我们一刀切掉, 默认只能用udp开白名单, tcp流量我们全部允许(通过QQ匹配规则,后面还有适当的规则和那些规则的白名单),也就是说, 我们不进行tcp的白名单匹配, 只对udp开刀, 然后就有了第一步的优化, 先对网站的一些白名单优先放行, 然后放行53端口的流量.
-s IP -p tcp –dport 80 -j ACCEPT
-i eth1 -p udp –dport 53 -j ACCEPT
-p udp -j QQ_ACCEPT
然后对QQ_ACCEPT这个链进行处理, 效果变好一些了, 但是偶尔还是有延迟大情况, 比如流量很大的时候, 继续优化, 经过ntop和一些抓包发现其实udp的流量远远不止我们常见的dns和QQ流量, 还有很多大流量的udp通讯, 还是按照之前的原则, 我们有限匹配ACCEPT的流量. 都知道QQ是优先用udp的4000或者8000端口进行累加, 我们忽略前面的那些端口, 把大端口的udp流量放行即可. 在前面插入下面这个”放行条”:
-i eth1 -p udp -m multiport –dport 10000:65535 -j ACCEPT
效果又变好些了,而且效果比较明显.
#2013/06/24继续优化
人数多了,带宽大了,问题再次凸显,udp上传非常大,严重影响同事上网体验。
-A PREROUTING -p udp -m limit –limit 2000/sec -m multiport –dport 8100:65535 -j ACCEPT
-A PREROUTING -p udp -m limit –limit 2000/sec -m multiport –dport 4100:7999 -j ACCEPT
-A PREROUTING -p udp -m limit –limit 2000/sec -m multiport –dport 1000:3999 -j ACCEPT
-A PREROUTING -p udp -m multiport –dport 8100:65535 -j DROP
-A PREROUTING -p udp -m multiport –dport 4100:7999 -j DROP
-A PREROUTING -p udp -m multiport –dport 1000:3999 -j DROP
即非QQ端口的udp协议包进行上传限速处理, 但是不能完全封禁, 因为有些正常应用还是需要udp协议, 而且如果完全禁止的话, 一些软件会判断udp网络不通,然后使用tcp端口继续作恶,那个时候控制起来更加困难,因为大多数正常应用都是基于tcp端口的。加这个限速之后,整个办公网降低了一半的上传流量。
总的来说iptables还是很给力的. 如果只是普通的nat的话, 服务器是毫无压力, 进行多个规则匹配之后, 调整一下网卡中断的cpu亲和性也是会很有效果的. 不过呢, 也会有个极限, 匹配的多了, 流量大了, 感觉cpu还是不够用, 偶尔会有些延迟增大情况,我们现在要做的就是把这个极限尽可能地增大。