不能只用 -j accept 放行回程流量,因为 iptables 依赖 conntrack 模块识别 established/related 状态,若未加载 nf_conntrack_ftp 等协议模块,ftp 数据连接等辅助流无法被正确标记,导致回程包被丢弃。

为什么不能只用 -j ACCEPT 放行回程流量
直接对所有 ESTABLISHED 状态包写一条 -j ACCEPT 规则看似合理,但实际会漏掉关键连接——比如 FTP 主动模式下的数据通道、SIP 的 RTP 流、甚至某些 NAT 后的 UDP 会话。这是因为 Linux 内核的连接跟踪(conntrack)模块判断“已建立”依赖于协议状态机,而 iptables 自身不维护连接状态;它只是查 conntrack 的实时表。若没有加载 nf_conntrack_ftp 等辅助模块,FTP 控制连接建好后,数据连接根本不会被标记为 RELATED 或 ESTABLISHED,回程包直接被 DROP。
必须加载的内核模块和检查方法
确保以下模块已载入,否则 state 或 conntrack 匹配将失效:
-
nf_conntrack(基础连接跟踪) -
nf_conntrack_ipv4(IPv4 支持) - 协议扩展模块,如
nf_conntrack_ftp、nf_conntrack_sip(按需)
检查命令:lsmod | grep nf_conntrack。若缺失,用 modprobe nf_conntrack_ftp 加载;永久生效需写入 /etc/modules 或对应 .conf 文件。
推荐写法:用 ctstate 替代过时的 state 模块
state 模块在较新内核中已被弃用,应改用 conntrack 模块的 --ctstate 参数。它更准确,且能区分 INVALID、UNTRACKED 等状态。
典型放行规则(放在 INPUT 链靠前位置):
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
注意点:
- 必须放在所有显式拒绝规则(如
-j DROP)之前,否则无效 -
RELATED不可省略——它覆盖由主连接触发的辅助连接(如 FTP 数据端口、ICMP 错误报文) - 不要加
--ctstate INVALID,这类包本就不该被接受,应后续显式DROP - 若系统启用了 IPv6,还需对
ip6tables做同样配置
验证是否生效:看 conntrack 表,别只盯 iptables 计数器
仅看 iptables -L -v 的包计数容易误判——可能规则命中了,但连接根本没进 conntrack 表。真正要看:
运行 conntrack -L,观察目标连接是否出现在输出中,且状态为 ESTABLISHED 或 RELATED。例如发起一个 SSH 连接后,应看到类似:
tcp 6 431999 ESTABLISHED src=192.168.1.100 dst=192.168.1.1 sport=54321 dport=22 ...
如果完全看不到条目,说明连接未被跟踪,得回头检查模块加载、或是否被 raw 表中的 NOTRACK 规则跳过。
conntrack 表满、或内核参数 net.netfilter.nf_conntrack_max 设得太小,也会导致新连接不被跟踪——这点常被忽略。











