linux nat转发失败主因是iptables/nftables规则顺序错误、表匹配错位或conntrack状态干扰,需按prerouting→forward→postrouting路径逐段验证,检查drop/accept顺序、nat表误用filter、dnat被缓存连接绕过、snat出口网卡匹配缺失及内核转发参数是否持久生效。

Linux NAT转发失败,多数情况不是内核没开转发,而是 iptables/nftables 规则链顺序、表匹配逻辑或连接跟踪状态出了问题。重点看 PREROUTING → FORWARD → POSTROUTING 这条路径是否完整打通,且每个环节都匹配成功。
iptables 规则顺序错乱导致 NAT 不生效
iptables 是按顺序逐条匹配的,一旦某条规则提前 DROP 或 RETURN,后续的 SNAT/DNAT 就根本不会执行。常见错误包括:
- 在
FORWARD链开头就写了-j DROP,但没加允许转发的 ACCEPT 规则 - DNAT 规则放在
PREROUTING链末尾,而前面已有-j REJECT或-j DROP - 使用了
-t nat加规则,却误写到filter表里(比如iptables -A INPUT -t nat -j DNAT...语法非法且无效)
连接跟踪(conntrack)干扰 DNAT 后续转发
Linux 内核的 conntrack 模块会缓存连接状态。如果旧连接还在 conntrack 表中,即使你改了 DNAT 规则,已建立的连接仍按老路径走,新规则对它们不生效。
排查方法:
- 运行
conntrack -L | grep "dport=xxx"查看目标端口的连接是否存在 - 临时清空相关连接:
conntrack -D --dport 8080 --proto tcp - 确认
/proc/sys/net/netfilter/nf_conntrack_tcp_be_liberal是否为 1(避免因 TCP 窗口/ACK 异常被丢弃)
SNAT 地址伪装失败:出口网卡与源地址不匹配
做 SNAT(如让内网访问外网时统一用 eth0 地址)时,容易忽略匹配条件:
- 只写了
-s 192.168.1.0/24 -j SNAT --to-source 203.0.113.5,但没限定-o eth0,导致从其他接口出包时也触发,可能冲突 -
--to-source指定的 IP 不是本机实际配置在出口网卡上的地址(比如填了未启用的别名 IP) - 使用
MASQUERADE时,出口网卡动态获取 IP,但规则绑定了固定-o接口,而该接口恰好 down 了
内核参数未开启或被覆盖
虽然 /proc/sys/net/ipv4/ip_forward 是基础,但还有几个易被忽略的点:
- IPv6 转发需单独开启:
/proc/sys/net/ipv6/conf/all/forwarding - 某些发行版(如 CentOS/RHEL 8+)默认启用 nftables,iptables 命令只是兼容层,实际规则由 nft 解析,此时
iptables-save可能不显示真实生效规则 - NetworkManager 或 systemd-networkd 可能重置
ip_forward,需在/etc/sysctl.conf中固化并执行sysctl -p
不复杂但容易忽略。关键是在数据包路径上分段验证:用 tcpdump 抓包看 PREROUTING 前后目的 IP 是否变化,再查 FORWARD 是否放行,最后看 POSTROUTING 出口包源 IP 是否被正确替换。











