一年前,我写过一篇博文叫 ———— ip_conntrack: table full问题 ,当时是在squid应用主机上最先发现了该问题,也于当时,深刻了解到iptables的这个报错,会造成拒绝服务的问题。其后iptables重启 (重启会将该hash表存的值清空)、proc参数优化,临时解决了该问题 。并未进行细一步的研究 。随着centos 由5.X升级到6.X ,该模块的名字也由ip_conntrack变成了nf_conntrack 。两者的区别是,前者只支持ipv4,而后者增加了对ipv6的支持。

由于公司自身的推广到位,流量出现了倍增 。于是公司决定另选了两个机房,每个机房各放置一台主机做squid cache加速 。而运行过程中一直有一个小问题,就是偶尔会出现丢包的问题。当于以为是IDC的问题,一直让IDC去查原因,IDC那边并未查到原因 。这个问题就暂时搁置了。

同于又由于受近期金价暴跌的影响,网站流量由平时的80M/s 直接上升到250M/s ,这个ping丢包的问题变的尤为明显。而将加速应用指到数据机房的squid上时。同现出现了ping丢包的问题,这个不得不从自身找原因了。通过/var/log/message查看,发现老面孔 ———— ip_conntrack: table full 。看到该错误,首先关闭了iptables 。过了一两分钟后,神奇的丢包问题没了。汗 ……

至此开始真正开始关注此问题。总结了下网上对该问题的处理方式有三种。

方法一:修改参数法

这个方法我在一年前就已经用过。如下:

1vim /etc/sysctl.conf
2#加大 ip_conntrack_max 值
3net.ipv4.ip_conntrack_max = 393216
4net.ipv4.netfilter.ip_conntrack_max = 393216
5#降低 ip_conntrack timeout时间
6net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 300
7net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait = 120
8net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait = 60
9net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait = 120

增加完以上内容后,通过sysctl -p 使配置生效 。不过该方法有两个缺点:一是重启iptables后,ip_conntrack_max值又会变成65535默认值,需要重新sysctl -p ;另一个是该法治标不治本,在高并发时,很快又会悲剧重演。

方法二:使用RAW表,跳过记录法

首先先认识下什么是raw表?做什么用的?

iptables有5个链:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING,4个表:filter,nat,mangle,raw 。

4个表的优先级由高到低的顺序为:raw–>mangle–>nat–>filter

举例来说:如果PRROUTING链上,即有mangle表,也有nat表,那么先由mangle处理,然后由nat表处理 。

RAW表只使用在PREROUTING链和OUTPUT链上,因为优先级最高,从而可以对收到的数据包在连接跟踪前进行处理。一但用户使用了RAW表,在某个链上,RAW表处理完后,将跳过NAT表和 ip_conntrack处理,即不再做地址转换和数据包的链接跟踪处理了。

RAW表可以应用在那些不需要做nat的情况下,以提高性能。如大量访问的web服务器,可以让80端口不再让iptables做数据包的链接跟踪处理,以提高用户的访问速度 。

具体操作方法如下:

1、修改/etc/sysconfig/iptables 文件中的-A RH-Firewall-1-INPUT -m state –state RELATED,ESTABLISHED, UNTRACKED -j ACCEPT 行。增加红色字体中的部分,保存并restart iptables 。

2、运行下面的语句:

1iptables -t raw -A PREROUTING -p tcp -m multiport --dports 80,3128 -j NOTRACK
2iptables -t raw -A PREROUTING -p tcp -m multiport --sports 80,3128 -j NOTRACK
3iptables -t raw -A OUTPUT -p tcp -m multiport --dports 80,3128 -j NOTRACK
4iptables -t raw -A OUTPUT -p tcp -m multiport --sports 80,3128 -j NOTRACK

如果只是一个端口,改为下面的语句:

1iptables -t raw -A PREROUTING -p tcp -m tcp --dport 80 -j NOTRACK
2iptables -t raw -A OUTPUT -p tcp -m tcp --sport 80 -j NOTRACK
3iptables -t raw -A PREROUTING -p tcp -m tcp --sport 80 -j NOTRACK
4iptables -t raw -A OUTPUT -p tcp -m tcp --dport 80 -j NOTRACK

注:第1步很重要,如果第1处没改,执行后面的语句会造成相应的端口不能访问。我使用该方法时,就因为没有执行第一步的操作,造成web访问不能使用。

方法三:移除模块法

1[root@localhost log]# /sbin/lsmod | egrep 'ip_tables|conntrack'
2nf_conntrack_ipv6       8748  2
3nf_defrag_ipv6         12182  1 nf_conntrack_ipv6
4nf_conntrack           79453  2 nf_conntrack_ipv6,xt_state
5ipv6                  322541  209 ip6t_REJECT,nf_conntrack_ipv6,nf_defrag_ipv6

执行上面的语句,不难发现state模块和nf_conntrack之间是有依赖关系的。所以想要卸载nf_conntrack模块的话,必须也要把state模块移除,不然,其会自动启用nf_conntrack模块。

操作方法如下:

1、先将/etc/sysconfig/iptables 中包含state的语句移除,并restart iptables 。
2、执行语句

1modprobe -r xt_NOTRACK nf_conntrack_netbios_ns nf_conntrack_ipv4 xt_state
2modprobe -r nf_conntrack

执行完查看/proc/net/ 下面如果没用了 nf_conntrack ,就证明模块移除成功了。

总结:

以上三种方法种,如果像web这样的操作访问量并发不大的情况下,建议通过第一种方法实现。因为nf_conntrack模块的作用不仅仅只用于记录状态,iptables还可以通过对该模块的使有达到动态过滤的作用。如我在用ab动测试的一台服务器上进行并发模拟时,在/var/log/message里发现如下的日志:

1Apr 22 15:21:46 localhost kernel: possible SYN flooding on port 80. Sending cookies.
2Apr 22 15:22:46 localhost kernel: possible SYN flooding on port 80. Sending cookies.

而此时iptables会智能的将发动SYN flood攻击的IP暂时拒绝掉:

1[root@localhost ~]# ab -c 500 -n 5000 "http://192.168.10.177/"
2This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
3Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
4Copyright 2006 The Apache Software Foundation, http://www.apache.org/
5Benchmarking 192.168.10.177 (be patient)
6apr_socket_recv: Connection reset by peer (104)
7Total of 68 requests completed

如上所以,我用ab操作时,其就会收到apr_socket_recv 的错误提示 。我在网上查询到其具体实现的原理如下:

传统的防火墙只能进行静态过滤,而 iptables 除了这个基本的功能之外还可以进行动态过滤,即可以对连接状态进行跟踪,通常称为 conntrack 。 但这不意味着它只能对 TCP 这样的面向连接的协议有效,它还可以对 UDP, ICMP 这种无连接的协议进行跟踪,我们下面马上就会看到。

iptables 中的连接跟踪是通过 state 模块来实现的,是在PREROUTING 链中完成的,除了本地主机产生的数据包,它们是在 OUTPUT 链中完成。 它把“连接”划分为四种状态:NEW, ESTABLISHED, RELATED 和 INVALID。连接跟踪当前的所有连接状态可以通过 /proc/net/nf_conntrack 来查看(注意,在一些稍微旧的 Linux 系统上是 /proc/net/ip_conntrack)。

当 conntrack 第一次看到相关的数据包时,就会把状态标记为 NEW ,比如 TCP 协议中收到第一个 SYN 数据包。当连接的双方都有数据包收发并且还将继续匹配到这些数据包时,连接状态就会变为 ESTABLISHED 。而 RELATED 状态是指一个新的连接,但这个连接和某个已知的连接有关系,比如 FTP 协议中的数据传输连接。INVALID 状态是说数据包和已知的任何连接都不匹配。

当然,仅仅利用iptables conntrack自动实现syn flood 等DDOS攻击时很弱的。而现成的动态过滤和DDOS防护的方法是很多的。比如netstat脚本实现,iptalbes限制每秒进行连接数,nginx/apache的连接数限制模块及fail2ban日志分析法………… ,所以在具有以上防护的情况下,非常推荐将web 、squid/varnish等应用所在的服务器配置为RAW方式 。我在现网一台150M/S 的cache server上将80和3128两个端口全部NOTRACK之后,conntrack hash表由瞬满直线下降到只有几百条。

最后,最不推荐使用的第三种方法,因为第三种方法会将state模块也一块儿移除掉。

参考页面:

http://jaseywang.me/2012/08/16/%E8%A7%A3%E5%86%B3-nf_conntrack-table-full-dropping-packet-%E7%9A%84%E5%87%A0%E7%A7%8D%E6%80%9D%E8%B7%AF/

http://wiki.khnet.info/index.php/Conntrack_tuning

http://blog.zol.com.cn/2608/article_2607945.html

http://wangcong.org/articles/learning-iptables.cn.html

http://pc-freak.net/blog/resolving-nf_conntrack-table-full-dropping-packet-flood-message-in-dmesg-linux-kernel-log/

http://blog.csdn.net/dog250/article/details/7262619