iptables连接跟踪状态表conntrack爆满网络故障处理[已解决]
本文记录了Openwrt 软路由,由于iptables连接跟踪状态表conntrack达到最大限制,触发一系列奇怪的网络。从故障现象到排查过程,
到优化方案都做了详细的总结
首先介绍下公司的网络设备连接方式:
问题描述:某天接到公司同事反馈 IOS端的 Appstore应用打不开。一开始以为是同事电脑问题。
报错如下:
故按照管理,重启大法伺候,
重启完之后,故障仍在。没多久,又有其他同事陆续范围,MAC笔记本电脑打不开 Appstore,断网重连,重启电脑都不行。
看来网络确实有问题。
开始排查
排查接入点网络
先尝试有线和无线,2.4G和5G两个WIFI频段都尝试一次,以上问故障都会出现。初步定位为和WIFI热点无关。应该是上层网络节点出问题。
排查路由防火墙设置
排查了常规的iptables防火墙,端口转发,行为管理行为策略。发现都正常。
路由器tcpdump抓包
登录openwrt路由器命令行界面,使用tcpdump -vn 192.168.24.31 抓包debug
这里的 192.168.24.31 是其中的一台苹果手机IP,我们用这台手机访问appstore抓包测试。经排查发现打开appstore 这个app时网络数据包异常,从app服务器发来的udp数据包,无法被手机端接收,服务器发来的3次同样的Udp数据包,均没有被手机端接收到。
问题就出在这里。那么是什么原因导致的呢?
考虑到既然是网络数据包进不来,重置一下网络连接是否有效呢?
然后在openwrt上面重载iptables,再测试发现app store可以正常访问了。
然而。。。,过了1分钟之后,app store就又无法访问了,一脸懵逼。。。
看来这个问题确实跟防火墙有关。
防火墙上配置了一系列端口转发规则,都是业务在用的,无法通过关闭Iptables解决。
在这里卡了大半天,实在找不到解决办法。并且在这期间app store有时候是能访问的,大部分时间都无法访问。看起来相当不稳定,很奇怪的问题。
这里就想着如何追踪iptables工作状态,经过查资料发现。
openwrt 网络连接主要和iptables有关,并且记录在 /proc/net/nf_conntrack 中,这个文件中。
nf_conntrack详解
nf_conntrack(在老版本的 Linux 内核中叫 ip_conntrack)是一个内核模块,用于跟踪一个连接的状态的。连接状态跟踪可以供其他模块使用,最常见的两个使用场景是 iptables 的 nat 的 state 模块。
iptables 的 nat 通过规则来修改目的/源地址,但光修改地址不行,我们还需要能让回来的包能路由到最初的来源主机。这就需要借助 nf_conntrack 来找到原来那个连接的记录才行。而 state 模块则是直接使用 nf_conntrack 里记录的连接的状态来匹配用户定义的相关规则。例如下面这条 INPUT 规则用于放行 80 端口上的状态为 NEW 的连接上的包。
iptables -A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT。
iptables中的状态检测功能是由state选项来实现iptable的
/proc/net/nf_conntrack内容详解
cat /proc/net/nf_conntrack
ipv4 2 tcp 6 8 CLOSE src=115.231.78.3 dst=107.173.34.159 sport=64904 dport=443 src=107.173.34.159 dst=115.231.78.3 sport=443 dport=64904 [ASSURED] mark=0 zone=0 use=2
ipv4 2 tcp 6 119 TIME_WAIT src=115.231.78.3 dst=107.173.34.159 sport=45761 dport=443 src=107.173.34.159 dst=115.231.78.3 sport=443 dport=45761 [ASSURED] mark=0 zone=0 use=2
ipv4 2 tcp 6 6 CLOSE src=115.231.78.3 dst=107.173.34.159 sport=57985 dport=443 src=107.173.34.159 dst=115.231.78.3 sport=443 dport=57985 [ASSURED] mark=0 zone=0 use=2
每一列表达的意思
第一列:网络层协议名字。
第二列:网络层协议号。
第三列:传输层协议名字。
第四列:传输层协议号。
第五列:无后续包进入时无效的秒数,即老化时间。
第六列:不是所有协议都有,连接状态。
其它的列都是通过名字的方式(key与value对)表述,或和呈现标识([UNREPLIED], [ASSURED], …)。一行的不同列可能包含相同的名字(例如src和dst),第一个表示请求方,第二个表示应答方。
呈现标识含义
[ASSURED]: 在两个方面(即请求和响应)方向都看到了流量。
[UNREPLIED]: 尚未在响应方向上看到流量。如果连接跟踪缓存溢出,则首先删除这些连接。
请注意,某些列名仅出现在特定协议中(例如,TCP和UDP的sport和dport,ICMP的type和code)。 仅当内核使用特定选项构建时,才会显示其他列名称(例如mark)。
经检查发现,这个文件现在有16000行左右。这个值刚好和当前配置的
net.netfilter.nf_conntrack_max=16000 值接近,并且一直在这个值左右徘徊。查阅资料发现这个值是系统用来记录跟踪所有网络连接状态的表。已经超过了最大值。我们修改并添加一下参数再试试:
在 /etc/sysctl.conf 文件中新增以下内容
net.netfilter.nf_conntrack_buckets=262144
net.netfilter.nf_conntrack_generic_timeout=600
net.netfilter.nf_conntrack_udp_timeout=30
net.netfilter.nf_conntrack_udp_timeout_stream=180
net.netfilter.nf_conntrack_tcp_timeout_syn_recv=60
net.netfilter.nf_conntrack_tcp_timeout_syn_sent=120
net.netfilter.nf_conntrack_tcp_timeout_time_wait=120
然后:
sysctl -w net.netfilter.nf_conntrack_buckets=262144
sysctl -w net.netfilter.nf_conntrack_generic_timeout=600
sysctl -w net.netfilter.nf_conntrack_udp_timeout=30
sysctl -w net.netfilter.nf_conntrack_udp_timeout_stream=180
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_recv=60
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_sent=120
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=120
使之生效。
再运行 sysctl -p
以防万一。找个业务低峰期重启一下openwrt,重启速度openwrt硬件有关。我们的硬件为inter 10代i7,30秒左右就重启好了。
经过2天的观察,发现app store已经完全正常, /proc/net/nf_conntrack 文件记录数也从1.6w,涨到了2w看起来确实生效了。收工。
评论 (0)