Skip to content

🔍 conntrack 连接追踪

什么是连接追踪?

防火墙要判断一个数据包是"新连接"还是"已有连接的后续包",靠的就是 conntrack(Connection Tracking)。它维护一张连接表,记录每个连接的状态。

这就是为什么你经常看到 -m state --state ESTABLISHED,RELATED -j ACCEPT——它允许已建立连接的回包通过,省去了为每个方向都写规则的麻烦。

💡 提示: 💡 三种状态:NEW— 第一个包,新连接的开始ESTABLISHED— 连接已建立,双向都有数据RELATED— 与已有连接相关(如 FTP 数据通道、ICMP 错误)还有一个INVALID— 无法识别的包,通常直接丢弃。

查看连接追踪表

bash
# 查看所有追踪的连接
conntrack -L
tcp  6 431999 ESTABLISHED src=192.168.1.100 dst=10.0.0.50 sport=54321 dport=80 src=10.0.0.50 dst=192.168.1.100 sport=80 dport=54321 [ASSURED] use=1
udp  17 29 src=192.168.1.100 dst=8.8.8.8 sport=12345 dport=53 src=8.8.8.8 dst=192.168.1.100 sport=53 dport=12345 use=1

# 只看 TCP 连接
conntrack -L -p tcp

# 只看某个 IP 的连接
conntrack -L -s 192.168.1.100

# 统计连接数
conntrack -C
247

# 查看内核允许的最大追踪数
sysctl net.netfilter.nf_conntrack_max
net.netfilter.nf_conntrack_max = 262144

⚠️ 注意: ⚠️ 连接数满了会怎样?如果追踪表满了(达到 nf_conntrack_max),新连接会被直接丢弃!你的服务器会突然"断网"——SSH 断开、网站打不开,但 ping 可能还通。这是生产环境常见的"诡异故障"之一。

调整连接追踪参数

bash
# 查看当前值
sysctl net.netfilter.nf_conntrack_max
sysctl net.netfilter.nf_conntrack_tcp_timeout_established

# 临时调整(重启失效)
sysctl -w net.netfilter.nf_conntrack_max=524288
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=3600

# 永久生效——写入 /etc/sysctl.conf
cat >> /etc/sysctl.conf << 'EOF'
# conntrack 优化
net.netfilter.nf_conntrack_max = 524288
net.netfilter.nf_conntrack_tcp_timeout_established = 3600
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 15
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 30
EOF

sysctl -p

# 监控追踪表使用率
watch -n 2 'conntrack -C && echo "/ $(sysctl -n net.netfilter.nf_conntrack_max)"'

💡 提示: 💡 经验值:普通 Web 服务器:524288(默认的 2 倍)高流量 Nginx 反代:1048576数据库服务器:默认值通常够用TIME_WAIT 超时从默认 120s 降到 30s,能回收大量"僵尸连接"

conntrack 与性能

conntrack 不是免费的——每个连接都要在内核里占一条记录。以下场景要特别注意:

场景问题解决方案
NAT 网关所有内网流量都经过 conntrack,表很容易满增大 nf_conntrack_max + 优化超时
高并发 Web短连接大量产生,追踪表压力大用NOTRACK跳过追踪 + keepalive
DNS 服务器大量 UDP 短连接UDP 超时设短(15-30s)
FTP 服务器RELATED 状态追踪额外开销加载 nf_conntrack_ftp 模块
bash
# 跳过特定流量的连接追踪(提高性能)
iptables -t raw -A PREROUTING -p tcp --dport 80 -j NOTRACK
iptables -t raw -A OUTPUT -p tcp --sport 80 -j NOTRACK

# 对应地,这些流量不能用 -m state 匹配
# 改用 -m conntrack --ctstate 或直接放行
iptables -A INPUT -p tcp --dport 80 -j ACCEPT