iptables 完全指南 / 第 10 章:连接跟踪机制
第 10 章:连接跟踪机制
本章目标:深入理解 Linux 连接跟踪(conntrack)的状态机,掌握 ESTABLISHED、RELATED、NEW、INVALID 四种状态的含义,学会使用 conntrack 工具调试连接问题。
10.1 连接跟踪概述
连接跟踪(Connection Tracking)是 Netfilter 框架的核心模块,它为每个经过防火墙的网络连接维护一条状态记录。通过连接跟踪,防火墙能够:
- 有状态过滤:只检查新连接的第一个包,后续包自动放行
- NAT 支持:NAT 依赖连接跟踪记录地址转换映射
- 协议辅助:跟踪 FTP、SIP 等多连接协议的关联连接
10.1.1 连接跟踪在数据包处理中的位置
数据包进入
│
▼
┌──────────────┐
│ raw 表 │ ← 可在此跳过连接跟踪(NOTRACK)
└──────┬───────┘
│
▼
┌──────────────┐
│ conntrack │ ← 创建/查找/更新连接跟踪条目
│ (NEW/ESTABLISHED/
│ RELATED/INVALID)
└──────┬───────┘
│
▼
┌──────────────┐
│ mangle 表 │
│ nat 表 │ ← NAT 使用连接跟踪记录
│ filter 表 │ ← filter 表使用 conntrack 状态匹配
└──────────────┘
10.2 连接状态详解
10.2.1 四种连接状态
| 状态 | 含义 | 触发条件 |
|---|---|---|
| NEW | 新连接的第一个包 | conntrack 表中没有该连接的记录 |
| ESTABLISHED | 已建立连接的后续包 | conntrack 表中已有该连接的双向通信记录 |
| RELATED | 与已有连接相关的新连接 | 辅助模块识别的关联连接(如 FTP 数据通道) |
| INVALID | 无法识别状态的数据包 | 无法解析或不属于任何已知连接 |
10.2.2 NEW 状态
# 匹配新连接
iptables -A INPUT -m conntrack --ctstate NEW -j ACCEPT
# TCP 的 NEW 状态:SYN 包
# UDP 的 NEW 状态:第一个数据包
# ICMP 的 NEW 状态:echo-request
注意:NEW 不代表连接一定会成功建立。一个 SYN 包是 NEW 状态,即使目标端口未开放。
10.2.3 ESTABLISHED 状态
# 匹配已建立连接的后续包
# TCP:看到双向通信(SYN + SYN-ACK 都出现)
# UDP:看到双向数据包
# ICMP:看到 echo-reply
iptables -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT
10.2.4 RELATED 状态
# 匹配与已有连接相关的新连接
iptables -A INPUT -m conntrack --ctstate RELATED -j ACCEPT
RELATED 状态的典型场景:
| 场景 | 主连接 | 关联连接 |
|---|---|---|
| FTP 主动模式 | 控制通道 (21) | 数据通道 (20) |
| FTP 被动模式 | 控制通道 (21) | 动态端口数据通道 |
| ICMP 错误 | 任何连接 | ICMP unreachable |
| SIP/RTP | SIP 信令 (5060) | RTP 媒体流 |
| TFTP | TFTP 请求 (69) | 动态端口数据传输 |
| Amanda 备份 | Amanda 控制 | Amanda 数据 |
# 加载 FTP 辅助模块(使 FTP 数据通道被识别为 RELATED)
modprobe nf_conntrack_ftp
# 加载 TFTP 辅助模块
modprobe nf_conntrack_tftp
# 加载 SIP 辅助模块
modprobe nf_conntrack_sip
10.2.5 INVALID 状态
# 记录无效数据包
iptables -A INPUT -m conntrack --ctstate INVALID \
-j LOG --log-prefix "IPT-INVALID: "
# 丢弃无效数据包
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
INVALID 状态的典型原因:
| 原因 | 说明 |
|---|---|
| 乱序 TCP 包 | 序列号不在窗口内 |
| ICMP 错误消息 | 不对应任何已知连接 |
| 内存不足 | conntrack 表满,无法创建新条目 |
| 协议异常 | 无法解析的数据包 |
10.3 TCP 连接状态机
10.3.1 TCP 三次握手与 conntrack
客户端 conntrack 服务器
│ │ │
│──── SYN ─────────→│ 记录: NEW │──── SYN ─────────→
│ │ 状态: SYN_SENT │
│ │ │
│←─── SYN+ACK ─────│ 更新: SYN_RECV │←─── SYN+ACK ──────
│ │ │
│──── ACK ─────────→│ 更新: ESTABLISHED │──── ACK ─────────→
│ │ │
│←─── 数据 ─────────│ ESTABLISHED │←─── 数据 ──────────
│ │ │
10.3.2 TCP 状态超时
| conntrack 状态 | 对应 TCP 状态 | 默认超时 |
|---|---|---|
SYN_SENT | SYN_SENT | 120 秒 |
SYN_RECV | SYN_RECV | 60 秒 |
ESTABLISHED | ESTABLISHED | 432000 秒(5天) |
FIN_WAIT | FIN_WAIT | 120 秒 |
CLOSE_WAIT | CLOSE_WAIT | 60 秒 |
LAST_ACK | LAST_ACK | 30 秒 |
TIME_WAIT | TIME_WAIT | 120 秒 |
CLOSE | CLOSED | 10 秒 |
# 查看当前 TCP 超时设置
sysctl -a | grep net.netfilter.nf_conntrack_tcp_timeout
# 优化高并发场景的超时
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=1800
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=15
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_fin_wait=15
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_close_wait=10
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_sent=15
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_syn_recv=10
10.4 conntrack 工具
10.4.1 查看连接跟踪表
# 查看所有连接跟踪条目
conntrack -L
# 按协议过滤
conntrack -L -p tcp
conntrack -L -p udp
conntrack -L -p icmp
# 按状态过滤
conntrack -L --state ESTABLISHED
conntrack -L --state NEW
# 按源 IP 过滤
conntrack -L -s 192.168.1.100
# 按目的端口过滤
conntrack -L -p tcp --dport 80
# 精确匹配
conntrack -L -p tcp --src 192.168.1.100 --dst 10.0.0.10 --dport 80
10.4.2 监控连接变化
# 实时监控新建/更新/销毁的连接
conntrack -E
# 输出示例:
# [NEW] tcp 6 120 SYN_SENT src=192.168.1.100 dst=10.0.0.10 sport=54321 dport=80
# [UPDATE] tcp 6 60 SYN_RECV src=192.168.1.100 dst=10.0.0.10 sport=54321 dport=80
# [UPDATE] tcp 6 432000 ESTABLISHED src=192.168.1.100 dst=10.0.0.10 sport=54321 dport=80
10.4.3 统计信息
# 查看当前连接跟踪条目数
conntrack -C
# 查看 conntrack 统计信息
conntrack -S
# 输出示例:
# packets 1234567
# bytes 987654321
# avg-pkt-size 800
# new 12345
# established 1220000
# invalid 123
# ignore 456
# delete 1100000
# delete_list 890
# insert 12345
# insert_failed 0
# drop 0
# early_drop 0
# error 0
# search_restart 0
10.4.4 删除连接跟踪条目
# 删除特定连接
conntrack -D -p tcp --dport 80 -s 192.168.1.100
# 删除所有 TCP 连接
conntrack -D -p tcp
# 清空所有连接跟踪(危险!会导致已建立连接丢失状态)
conntrack -F
# 删除特定状态的连接
conntrack -D --state TIME_WAIT
10.4.5 高级过滤
# 使用 Mark 过滤
conntrack -L -m 1
# 使用 Labels 过滤
conntrack -L --label web-traffic
# 查看 NAT 转换后的连接
conntrack -L -p tcp --src-nat
conntrack -L -p tcp --dst-nat
10.5 典型配置模式
10.5.1 基于状态的有状态防火墙
#!/bin/bash
# ═══════════════════════════════════════════════════
# 有状态防火墙(推荐配置)
# ═══════════════════════════════════════════════════
iptables -F
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# 核心规则:允许已建立和相关的连接
# 这条规则放在最前面,能匹配 90%+ 的数据包
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 丢弃无效包
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
# 允许回环接口
iptables -A INPUT -i lo -j ACCEPT
# 允许新连接:SSH
iptables -A INPUT -p tcp --dport 22 --syn \
-m conntrack --ctstate NEW -j ACCEPT
# 允许新连接:HTTP/HTTPS
iptables -A INPUT -p tcp -m multiport --dports 80,443 --syn \
-m conntrack --ctstate NEW -j ACCEPT
# 允许新连接:ICMP
iptables -A INPUT -p icmp --icmp-type echo-request \
-m conntrack --ctstate NEW -j ACCEPT
# 日志并丢弃其他
iptables -A INPUT -j LOG --log-prefix "IPT-DROP: "
iptables -A INPUT -j DROP
10.5.2 FTP 被动模式支持
#!/bin/bash
# FTP 服务器防火墙配置(被动模式)
# 加载 FTP 连接跟踪辅助模块
modprobe nf_conntrack_ftp
modprobe nf_nat_ftp
# 持久化加载
echo "nf_conntrack_ftp" >> /etc/modules-load.d/ftp.conf
echo "nf_nat_ftp" >> /etc/modules-load.d/ftp.conf
# 允许已建立的连接和 RELATED(FTP 数据通道)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 允许 FTP 控制通道
iptables -A INPUT -p tcp --dport 21 -j ACCEPT
# 允许 FTP 被动模式数据端口范围
iptables -A INPUT -p tcp --dport 30000:31000 -j ACCEPT
# 允许 FTP 主动模式数据通道(由 conntrack_ftp 自动识别为 RELATED)
# 不需要额外规则
iptables -P INPUT DROP
10.5.3 SIP/VoIP 防火墙
#!/bin/bash
# VoIP 服务器防火墙配置
# 加载 SIP 辅助模块
modprobe nf_conntrack_sip
modprobe nf_nat_sip
# 允许 SIP 信令
iptables -A INPUT -p udp --dport 5060 -j ACCEPT
iptables -A INPUT -p tcp --dport 5060 -j ACCEPT
# 允许 RTP 媒体流(由 conntrack_sip 自动识别为 RELATED)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# RTP 端口范围(备用,如果辅助模块不生效)
iptables -A INPUT -p udp --dport 10000:20000 -j ACCEPT
10.6 conntrack 内核参数参考
10.6.1 核心参数
| 参数 | 默认值 | 建议值 | 说明 |
|---|---|---|---|
nf_conntrack_max | 65536 | 262144 | 最大连接跟踪条目数 |
nf_conntrack_buckets | 16384 | 65536 | 哈希桶数 |
nf_conntrack_tcp_timeout_established | 432000 | 1800 | TCP 已建立连接超时(秒) |
nf_conntrack_tcp_timeout_time_wait | 120 | 15 | TIME_WAIT 超时 |
nf_conntrack_udp_timeout | 30 | 10 | UDP 超时 |
nf_conntrack_icmp_timeout | 30 | 10 | ICMP 超时 |
nf_conntrack_generic_timeout | 600 | 120 | 通用超时 |
# 一次性优化 conntrack 参数
cat >> /etc/sysctl.conf << 'EOF'
# conntrack 性能优化
net.netfilter.nf_conntrack_max = 262144
net.netfilter.nf_conntrack_tcp_timeout_established = 1800
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 15
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 15
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 10
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 15
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 10
net.netfilter.nf_conntrack_udp_timeout = 10
net.netfilter.nf_conntrack_udp_timeout_stream = 60
net.netfilter.nf_conntrack_icmp_timeout = 10
net.netfilter.nf_conntrack_generic_timeout = 120
EOF
sysctl -p
10.7 故障排查
10.7.1 conntrack 表满
# 检查是否出现 conntrack 表满
dmesg | grep "nf_conntrack: table full"
# 检查使用率
COUNT=$(cat /proc/sys/net/netfilter/nf_conntrack_count)
MAX=$(cat /proc/sys/net/netfilter/nf_conntrack_max)
echo "使用率: $COUNT / $MAX ($(( COUNT * 100 / MAX ))%)"
# 查看哪些 IP 占用最多连接
conntrack -L | awk '{print $5}' | cut -d= -f2 | sort | uniq -c | sort -rn | head -20
# 查看哪些端口连接最多
conntrack -L | awk '{print $8}' | cut -d= -f2 | sort | uniq -c | sort -rn | head -20
10.7.2 DNAT 规则不生效
# 症状:修改 DNAT 规则后旧连接仍然走旧路径
# 原因:conntrack 缓存了旧的 NAT 映射
# 解决:清除相关连接跟踪条目
conntrack -D -p tcp --dport 80
10.7.3 RELATED 状态不识别
# 症状:FTP 数据通道被误判为 NEW 状态并被拒绝
# 原因:未加载 FTP 辅助模块
# 检查辅助模块
lsmod | grep nf_conntrack_ftp
# 加载模块
modprobe nf_conntrack_ftp
10.8 注意事项
⚠️ ESTABLISHED 不等于 TCP ESTABLISHED:conntrack 的 ESTABLISHED 状态指的是"conntrack 看到了双向通信",与 TCP 的 ESTABLISHED 状态含义不同。
⚠️ conntrack 表满会导致 NAT 失败:当 conntrack 表满时,新连接无法创建跟踪条目,NAT 转换会失败,数据包可能被错误处理。
⚠️ conntrack -F 的风险:清空 conntrack 表会导致所有已建立连接的状态信息丢失。如果有 NAT,NAT 映射也会丢失,导致已有连接中断。
⚠️ NOTRACK 与 ESTABLISHED 不兼容:被 NOTRACK 标记的数据包不会进入 conntrack,因此不能使用 ESTABLISHED/RELATED 状态匹配。
10.9 扩展阅读
| 资源 | 说明 |
|---|---|
man conntrack | conntrack 工具手册 |
man conntrackd | 连接跟踪同步守护进程 |
/proc/net/nf_conntrack | 内核 conntrack 表文件 |
/proc/net/stat/nf_conntrack | conntrack 统计信息 |
本章小结
| 状态 | 含义 | 典型用途 |
|---|---|---|
| NEW | 新连接的第一个包 | 限制新连接速率 |
| ESTABLISHED | 已建立连接的后续包 | 放行已建立的连接 |
| RELATED | 关联的新连接 | FTP/SIP/ICMP 错误 |
| INVALID | 无法识别的包 | 丢弃异常数据包 |
下一章:第 11 章:端口转发与代理,将学习端口转发、负载均衡和透明代理的实现方法。