如何修复Linux路由器的NAT流量转发异常问题
看起来你的Linux路由器的NAT转发突然掉链子了,别着急,咱们结合你的情况一步步排查解决:
1. 先确认NAT核心的POSTROUTING规则是否存在
你只贴了NAT表的PREROUTING链,但真正负责把内网流量伪装成外网IP的是POSTROUTING链。很多时候这类问题都是之前的MASQUERADE/SNAT规则莫名其妙丢了。
你可以先执行这条命令查看POSTROUTING链的详细情况:
iptables -t nat -L POSTROUTING -v
如果看不到针对10.0.0.0/16网段的MASQUERADE规则,那就手动补上(记得把<外网接口>替换成你连接192.168.1.x网段的实际接口,比如eth0、enp0s3之类的):
iptables -t nat -A POSTROUTING -o <外网接口> -s 10.0.0.0/16 -j MASQUERADE
这条规则的作用是:所有从内网10.0.x.x来的流量,从外网接口出去时自动替换成路由器的外网IP,这样外网服务器的响应才能找回来。
2. 检查filter表的FORWARD链是否拦截了流量
就算ip_forward已经开了,如果防火墙的FORWARD链拒绝了转发流量,数据包也走不通。你可以执行这条命令查看FORWARD链的规则:
iptables -L FORWARD -v
正常情况下需要两条关键规则:
- 允许内网流量发往外网:
iptables -A FORWARD -i <内网接口> -o <外网接口> -s 10.0.0.0/16 -j ACCEPT - 允许外网的响应流量回到内网(依赖连接追踪):
iptables -A FORWARD -i <外网接口> -o <内网接口> -m state --state RELATED,ESTABLISHED -j ACCEPT
如果你的FORWARD链默认是DROP,那这两条规则必须要有;如果默认是ACCEPT,那也要确保没有其他规则优先拒绝了这些流量。
3. 排查Docker对iptables的干扰
从你贴的NAT表输出能看到DOCKER链,Docker启动时会自动修改iptables规则,有时候会打乱原本的NAT转发逻辑。你可以先临时停止Docker服务试试:
systemctl stop docker
如果停了之后客户端能正常ping通外网,那就是Docker的锅。这时候你可以调整Docker的配置:
- 编辑
/etc/docker/daemon.json,添加"iptables": false(但这样Docker容器的外部网络访问会受影响,适合不需要Docker对外暴露端口的场景); - 或者调整iptables规则的优先级,确保你的NAT规则在Docker链之前生效。
4. 确认路由器自身的外网连通性和路由表
先在路由器上直接ping 8.8.8.8,如果路由器自己都ping不通,那问题不在转发,而是路由器本身的外网连接有问题。
再检查路由表有没有正确的默认路由:
ip route show
你需要看到类似这样的条目:default via 192.168.1.1 dev <外网接口>,这条是告诉路由器把所有非内网的流量发往192.168.1.x的网关。如果没有这条,就手动添加:
ip route add default via 192.168.1.1 dev <外网接口>
5. 检查反向路径过滤参数
有些时候rp_filter(反向路径过滤)的严格模式会导致响应包被路由器丢弃。你可以先临时关闭试试:
sysctl -w net.ipv4.conf.all.rp_filter=0
如果客户端能正常访问外网了,再把这个配置永久写入:编辑/etc/sysctl.conf或者/etc/sysctl.d/99-custom.conf,添加net.ipv4.conf.all.rp_filter=0,然后执行sysctl -p生效。
备注:内容来源于stack exchange,提问作者jnasworld223

