<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[沧海一粟]]></title> 
<link>http://www.dzhope.com/index.php</link> 
<description><![CDATA[Web系统架构与服务器运维,php开发]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[沧海一粟]]></copyright>
<item>
<link>http://www.dzhope.com/post//</link>
<title><![CDATA[用iptables的raw表解决ip_conntrack: table full, dropping packet的问题]]></title> 
<author>jed &lt;jed521@163.com&gt;</author>
<category><![CDATA[服务器技术]]></category>
<pubDate>Thu, 18 Jul 2013 21:47:52 +0000</pubDate> 
<guid>http://www.dzhope.com/post//</guid> 
<description>
<![CDATA[ 
	1)&nbsp;&nbsp;什么是raw表？做什么用的？<br/><br/>iptables有5个链:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING,4个表:filter,nat,mangle,raw.<br/><br/>4个表的优先级由高到低的顺序为:raw-->mangle-->nat-->filter<br/><br/>举例来说:如果PRROUTING链上,即有mangle表,也有nat表,那么先由mangle处理,然后由nat表处理<br/><br/>RAW表只使用在PREROUTING链和OUTPUT链上,因为优先级最高，从而可以对收到的数据包在连接跟踪前进行处理。一但用户使用了RAW表,在某个链上,RAW表处理完后,将跳过NAT表和 ip_conntrack处理,即不再做地址转换和数据包的链接跟踪处理了.<br/><br/>RAW表可以应用在那些不需要做nat的情况下，以提高性能。如大量访问的web服务器，可以让80端口不再让iptables做数据包的链接跟踪处理，以提高用户的访问速度。<br/><br/>2)&nbsp;&nbsp;iptables的数据包的流程是怎样的？<br/><br/>(流程介绍来源：<a href="http://selboo.com.cn/post/721/)" target="_blank">http://selboo.com.cn/post/721/)</a><br/>一个数据包到达时,是怎么依次穿过各个链和表的（图）。 <br/><br/><a href="http://www.dzhope.com/attachment.php?fid=69" target="_blank"><img src="http://www.dzhope.com/attachment.php?fid=69" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>基本步骤如下： <br/>1. 数据包到达网络接口，比如 eth0。 <br/>2. 进入 raw 表的 PREROUTING 链，这个链的作用是赶在连接跟踪之前处理数据包。 <br/>3. 如果进行了连接跟踪，在此处理。 <br/>4. 进入 mangle 表的 PREROUTING 链，在此可以修改数据包，比如 TOS 等。 <br/>5. 进入 nat 表的 PREROUTING 链，可以在此做DNAT，但不要做过滤。 <br/>6. 决定路由，看是交给本地主机还是转发给其它主机。 <br/><br/>到了这里我们就得分两种不同的情况进行讨论了，一种情况就是数据包要转发给其它主机，这时候它会依次经过： <br/>7. 进入 mangle 表的 FORWARD 链，这里也比较特殊，这是在第一次路由决定之后，在进行最后的路由决定之前，我们仍然可以对数据包进行某些修改。 <br/>8. 进入 filter 表的 FORWARD 链，在这里我们可以对所有转发的数据包进行过滤。需要注意的是：经过这里的数据包是转发的，方向是双向的。 <br/>9. 进入 mangle 表的 POSTROUTING 链，到这里已经做完了所有的路由决定，但数据包仍然在本地主机，我们还可以进行某些修改。 <br/>10. 进入 nat 表的 POSTROUTING 链，在这里一般都是用来做 SNAT ，不要在这里进行过滤。 <br/>11. 进入出去的网络接口。完毕。 <br/><br/>另一种情况是，数据包就是发给本地主机的，那么它会依次穿过： <br/>7. 进入 mangle 表的 INPUT 链，这里是在路由之后，交由本地主机之前，我们也可以进行一些相应的修改。 <br/>8. 进入 filter 表的 INPUT 链，在这里我们可以对流入的所有数据包进行过滤，无论它来自哪个网络接口。 <br/>9. 交给本地主机的应用程序进行处理。 <br/>10. 处理完毕后进行路由决定，看该往那里发出。 <br/>11. 进入 raw 表的 OUTPUT 链，这里是在连接跟踪处理本地的数据包之前。 <br/>12. 连接跟踪对本地的数据包进行处理。 <br/>13. 进入 mangle 表的 OUTPUT 链，在这里我们可以修改数据包，但不要做过滤。 <br/>14. 进入 nat 表的 OUTPUT 链，可以对防火墙自己发出的数据做 NAT 。 <br/>15. 再次进行路由决定。 <br/>16. 进入 filter 表的 OUTPUT 链，可以对本地出去的数据包进行过滤。 <br/>17. 进入 mangle 表的 POSTROUTING 链，同上一种情况的第9步。注意，这里不光对经过防火墙的数据包进行处理，还对防火墙自己产生的数据包进行处理。 <br/>18. 进入 nat 表的 POSTROUTING 链，同上一种情况的第10步。 <br/>19. 进入出去的网络接口。完毕。<br/><br/><br/>3)&nbsp;&nbsp;iptables raw表的使用<br/><br/>增加raw表，在其他表处理之前，-j NOTRACK跳过其它表处理<br/>状态除了以前的四个还增加了一个UNTRACKED<br/><br/>例如：<br/>可以使用 “NOTRACK” target 允许规则指定80端口的包不进入链接跟踪/NAT子系统<br/><br/>iptables -t raw -A PREROUTING -d 1.2.3.4 -p tcp --dport 80 -j NOTRACK<br/>iptables -t raw -A PREROUTING -s 1.2.3.4 -p tcp --sport 80 -j NOTRACK<br/>iptables -A FORWARD -m state --state UNTRACKED -j ACCEPT<br/><br/>4) 解决ip_conntrack: table full, dropping packet的问题<br/><br/><br/>在启用了iptables web服务器上，流量高的时候经常会出现下面的错误：<br/><br/>ip_conntrack: table full, dropping packet<br/><br/><br/>这个问题的原因是由于web服务器收到了大量的连接，在启用了iptables的情况下，iptables会把所有的连接都做链接跟踪处理，这样iptables就会有一个链接跟踪表，当这个表满的时候，就会出现上面的错误。<br/><br/>iptables的链接跟踪表最大容量为/proc/sys/net/ipv4/ip_conntrack_max，链接碰到各种状态的超时后就会从表中删除。<br/><br/>所以解決方法一般有两个：<br/><br/>(1) 加大 ip_conntrack_max 值<br/><br/>vi /etc/sysctl.conf<br/><br/>net.ipv4.ip_conntrack_max = 393216<br/>net.ipv4.netfilter.ip_conntrack_max = 393216<br/><br/><br/>(2): 降低 ip_conntrack timeout时间<br/><br/>vi /etc/sysctl.conf<br/><br/>net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = 300<br/>net.ipv4.netfilter.ip_conntrack_tcp_timeout_time_wait = 120<br/>net.ipv4.netfilter.ip_conntrack_tcp_timeout_close_wait = 60<br/>net.ipv4.netfilter.ip_conntrack_tcp_timeout_fin_wait = 120<br/><br/><br/>上面两种方法打个比喻就是烧水水开的时候，换一个大锅。一般情况下都可以解决问题，但是在极端情况下，还是不够用，怎么办？<br/><br/>这样就得反其道而行，用釜底抽薪的办法。iptables的raw表是不做数据包的链接跟踪处理的，我们就把那些连接量非常大的链接加入到iptables raw表。<br/><br/>如一台web服务器可以这样：<br/><br/>iptables -t raw -A PREROUTING -d 1.2.3.4 -p tcp --dport 80 -j NOTRACK<br/>iptables -A FORWARD -m state --state UNTRACKED -j ACCEPT<br/><br/><br/>5)&nbsp;&nbsp;iptables raw表的效果测试<br/><br/>我们在一台web server上做测试，先不使用raw表，观察链接跟踪表(/proc/net/ip_conntrack)的大小：<br/><br/>先看下iptables配置：<br/>cat /etc/sysconfig/iptables<br/><br/># Generated by iptables-save v1.3.5 on Wed Aug 18 10:10:52 2010<br/>*filter<br/>:INPUT ACCEPT [0:0]<br/>:FORWARD ACCEPT [0:0]<br/>:OUTPUT ACCEPT [104076:12500201]<br/>:RH-Firewall-1-INPUT - [0:0]<br/>-A INPUT -j RH-Firewall-1-INPUT<br/>-A FORWARD -j RH-Firewall-1-INPUT<br/>-A RH-Firewall-1-INPUT -i lo -j ACCEPT<br/>-A RH-Firewall-1-INPUT -p icmp -m icmp --icmp-type any -j ACCEPT<br/>-A RH-Firewall-1-INPUT -p esp -j ACCEPT<br/>-A RH-Firewall-1-INPUT -p ah -j ACCEPT<br/>-A RH-Firewall-1-INPUT -d 224.0.0.251 -p udp -m udp --dport 5353 -j ACCEPT<br/>-A RH-Firewall-1-INPUT -p udp -m udp --dport 631 -j ACCEPT<br/>-A RH-Firewall-1-INPUT -p tcp -m tcp --dport 631 -j ACCEPT<br/>-A RH-Firewall-1-INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT<br/>-A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT<br/>-A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT<br/>-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited<br/>COMMIT<br/># Completed on Wed Aug 18 10:10:52 2010<br/><br/>在另一台机器上用ab测试：<br/><br/>ab -c 1000 -n 5000 <a href="http://192.168.20.26/index.html" target="_blank">http://192.168.20.26/index.html</a><br/><br/>在web server上查看链接跟踪表(/proc/net/ip_conntrack)的大小：<br/><br/>[root@mongo html]# wc -l /proc/net/ip_conntrack<br/>5153 /proc/net/ip_conntrack<br/><br/>可以看到跟踪表内有5153个链接，再大一些的压力可能就要报ip_conntrack: table full, dropping packet的错误了。<br/><br/><br/>下面我们启用raw表：<br/><br/>先更新iptables：<br/><br/>[root@mongo html]# cat /etc/sysconfig/iptables<br/># Generated by iptables-save v1.3.5 on Wed Aug 18 10:10:52 2010<br/>*filter<br/>:INPUT ACCEPT [0:0]<br/>:FORWARD ACCEPT [0:0]<br/>:OUTPUT ACCEPT [104076:12500201]<br/>:RH-Firewall-1-INPUT - [0:0]<br/>-A INPUT -j RH-Firewall-1-INPUT <br/>-A FORWARD -j RH-Firewall-1-INPUT <br/>-A RH-Firewall-1-INPUT -i lo -j ACCEPT <br/>-A RH-Firewall-1-INPUT -p icmp -m icmp --icmp-type any -j ACCEPT <br/>-A RH-Firewall-1-INPUT -p esp -j ACCEPT <br/>-A RH-Firewall-1-INPUT -p ah -j ACCEPT <br/>-A RH-Firewall-1-INPUT -d 224.0.0.251 -p udp -m udp --dport 5353 -j ACCEPT <br/>-A RH-Firewall-1-INPUT -p udp -m udp --dport 631 -j ACCEPT <br/>-A RH-Firewall-1-INPUT -p tcp -m tcp --dport 631 -j ACCEPT <br/>-A RH-Firewall-1-INPUT -m state --state RELATED,ESTABLISHED,UNTRACKED -j ACCEPT <br/>-A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT <br/>-A RH-Firewall-1-INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT <br/>-A RH-Firewall-1-INPUT -j REJECT --reject-with icmp-host-prohibited <br/>COMMIT<br/># Completed on Wed Aug 18 10:10:52 2010<br/># Generated by iptables-save v1.3.5 on Wed Aug 18 10:10:52 2010<br/>*raw<br/>:PREROUTING ACCEPT [116163:9327716]<br/>:OUTPUT ACCEPT [104076:12500201]<br/>-A PREROUTING -p tcp -m tcp --dport 80 -j NOTRACK <br/>-A OUTPUT -p tcp -m tcp --sport 80 -j NOTRACK <br/>COMMIT<br/># Completed on Wed Aug 18 10:10:52 2010<br/><br/>红色部分是新增的。<br/><br/>重启iptables：<br/><br/>service iptables restart<br/><br/>可以用iptables命令查看是否启用成功了：<br/><br/>[root@mongo html]# iptables -t raw -L -n<br/>Chain PREROUTING (policy ACCEPT)<br/>target&nbsp;&nbsp;&nbsp;&nbsp; prot opt source&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; destination&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/>NOTRACK&nbsp;&nbsp;&nbsp;&nbsp;tcp&nbsp;&nbsp;--&nbsp;&nbsp;0.0.0.0/0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0.0.0.0/0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tcp dpt:80 <br/><br/>Chain OUTPUT (policy ACCEPT)<br/>target&nbsp;&nbsp;&nbsp;&nbsp; prot opt source&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; destination&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/>NOTRACK&nbsp;&nbsp;&nbsp;&nbsp;tcp&nbsp;&nbsp;--&nbsp;&nbsp;0.0.0.0/0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0.0.0.0/0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tcp spt:80 <br/><br/>然后再用ab测试：<br/><br/>ab -c 1000 -n 5000 <a href="http://192.168.20.26/index.html" target="_blank">http://192.168.20.26/index.html</a><br/><br/>查看链接跟踪表(/proc/net/ip_conntrack)的大小：<br/><br/>[root@mongo html]# wc -l /proc/net/ip_conntrack<br/>1 /proc/net/ip_conntrack<br/><br/>跟踪表内只跟踪了一个链接了。<br/><br/>[root@mongo html]# cat /proc/net/ip_conntrack&nbsp;&nbsp;<br/>tcp&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6 431999 ESTABLISHED src=192.168.20.26 dst=192.168.20.10 sport=22 dport=50088 packets=85 bytes=10200 src=192.168.20.10 dst=192.168.20.26 sport=50088 dport=22 packets=92 bytes=6832 [ASSURED] mark=0 secmark=0 use=1<br/><br/>可以看到iptables已经不跟踪进出端口为80的链接了。测试结果表明用iptables的raw表可以完美解决ip_conntrack: table full, dropping packet的问题。<br/>Tags - <a href="http://www.dzhope.com/tags/iptables/" rel="tag">iptables</a> , <a href="http://www.dzhope.com/tags/ip_conntrack/" rel="tag">ip_conntrack</a>
]]>
</description>
</item><item>
<link>http://www.dzhope.com/post//#blogcomment</link>
<title><![CDATA[[评论] 用iptables的raw表解决ip_conntrack: table full, dropping packet的问题]]></title> 
<author> &lt;user@domain.com&gt;</author>
<category><![CDATA[评论]]></category>
<pubDate>Thu, 01 Jan 1970 00:00:00 +0000</pubDate> 
<guid>http://www.dzhope.com/post//#blogcomment</guid> 
<description>
<![CDATA[ 
	
]]>
</description>
</item>
</channel>
</rss>