Fedora默认使用firewalld作为防火墙前端,但很多运维人员在实际工作中仍然习惯直接操作iptables。要真正理解iptables在Fedora上的行为,光会敲命令远远不够,必须弄清它底层的netfilter框架、四表五链结构以及规则在内核中的存放方式。这篇文章就从底层规则的角度,把iptables的工作机制彻底讲透。

一、netfilter框架:iptables规则的真正归宿
很多人以为iptables就是防火墙本身,这个理解是错误的。iptables只是一个用户态的命令行工具,真正干活的是Linux内核中的netfilter框架。当你在终端执行iptables -A INPUT -j DROP时,iptables工具通过socket接口与内核通信,把这条规则写进内核维护的规则链里,工具本身退出后规则依然生效,因为规则根本不存在于iptables程序中,而是存在于内核内存里。
netfilter在内核协议栈的关键位置埋设了五个钩子点,分别是PREROUTING、INPUT、FORWARD、OUTPUT和POSTROUTING。数据包流经网卡后,会在内核网络栈的不同阶段触发这些钩子,钩子上挂载的规则链就会对数据包进行过滤、修改或地址转换。理解这五个点的位置关系,是掌握iptables规则流向的基础。
数据包的处理路径大致是这样的:进入的数据包先经过PREROUTING链(做目的地址转换的时机),然后根据路由判断决定是发给本机还是转发。发给本机的走INPUT链,交给上层应用;需要转发的走FORWARD链。本机应用发出的包先经过OUTPUT链,最后无论是转发的还是本机发出的,都从POSTROUTING链离开(做源地址转换的时机)。
二、四表五链:规则的优先级与匹配顺序
iptables的规则按照表来分类,共四个表:raw、mangle、nat和filter。每个表的职责不同,raw表用于关闭连接跟踪,mangle表用于修改数据包的元信息,nat表做地址转换,filter表做过滤。关键点是,同一个钩子位置上可能同时挂着多个表的链,此时执行顺序是raw、mangle、nat、filter,这个优先级是内核写死的,无法通过命令调整。
举例来说,一个进入本机的数据包,会依次经过raw表的PREROUTING链、mangle表的PREROUTING链、nat表的PREROUTING链,最后到达filter表的INPUT链。如果你在nat表PREROUTING里做了DNAT,把目标地址改成了另一台机器,那这个包后续就不会走INPUT,而是被路由到FORWARD链。这就是为什么改地址的规则必须放在nat表,放在filter表里根本没有地址转换的能力。
链内部的规则匹配是自上而下的。iptables会按添加顺序逐条匹配,一旦命中某条规则并执行了终结性动作(如ACCEPT、DROP、REJECT),后面的规则就不再检查。所以规则的排列顺序非常重要,把宽泛的ACCEPT放在最前面,后面再写DROP就形同虚设。可以通过iptables -L INPUT --line-numbers查看带序号的规则列表,用iptables -I INPUT 2 ...把规则插入到指定位置。
三、Fedora上firewalld与iptables的共存关系
Fedora从很早的版本开始就默认预装firewalld,这是一个基于iptables(或nftables)后端的高级防火墙管理服务。这里有个非常常见的坑:如果你在firewalld运行的同时手动执行iptables命令添加规则,规则确实会生效,但一旦firewalld重载配置,你手动加的规则可能被清掉或覆盖。反过来,如果你用systemctl stop firewalld停掉firewalld再手动管理iptables,规则又完全可控。
更复杂的是,较新版本的Fedora中,iptables命令实际上是通过iptables-nft兼容层工作的,后端已经是nftables。也就是说,你输入的是iptables语法,内核里真正执行的却是nft规则。可以用iptables -V查看输出,如果显示带nft字样,说明走的就是兼容层。这种情况下nft list ruleset能看到包括firewalld和iptables共同生成的全部规则。
如果想纯粹使用传统iptables方式管理,可以先禁用firewalld,再安装iptables-services并启用:
# 停用firewalld systemctl stop firewalld systemctl disable firewalld # 安装并启用iptables服务 dnf install iptables-services -y systemctl enable --now iptables # 保存当前规则到配置文件,重启后自动加载 service iptables save # 规则保存在 /etc/sysconfig/iptables 中
保存之后,规则会被写入/etc/sysconfig/iptables文件,开机时由iptables服务自动加载,这样就摆脱了firewalld的干扰,规则的来源变得完全可控、可追溯。
四、filter表与nat表实操:从底层理解规则写法
先看filter表最基础的三条链:INPUT管进入本机的包,FORWARD管转发的包,OUTPUT管本机发出的包。一个典型的安全基线配置是:默认拒绝所有进入的流量,只放行明确需要的服务。注意REJECT和DROP的区别,REJECT会回一个拒绝报文让客户端立刻知道被拒,DROP则直接丢弃,客户端只能等待超时。对外暴露的服务一般用DROP更安全,因为不给对方任何探测反馈。
# 允许已建立连接和相关连接的包进入(关键的第一条) iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT # 允许本地环回接口 iptables -A INPUT -i lo -j ACCEPT # 放行SSH和HTTP iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -A INPUT -p tcp --dport 80 -j ACCEPT # 其余进入流量丢弃,并设为默认策略 iptables -P INPUT DROP iptables -P FORWARD DROP
这里第一条conntrack规则特别重要。连接跟踪是netfilter为每个连接维护的状态表,有了它,本机主动发起的出站连接,其回包会被自动识别为ESTABLISHED状态并放行。如果漏掉这条规则,一旦把INPUT默认策略设为DROP,你会发现本机ping不通外面、网页打不开,因为回包全被丢了。
再看nat表的两个典型用途。SNAT用在POSTROUTING链,通常用于内网机器通过网关上网时改写源地址;DNAT用在PREROUTING链,用于把访问网关某端口的外部流量转发到内网机器。
# 开启转发(写入内核参数) echo 1 > /proc/sys/net/ipv4/ip_forward # 内网192.168.10.0/24通过本机出站时做源地址伪装 iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth0 -j MASQUERADE # 外部访问本机8080端口,转发到内网10.0.0.8的80端口 iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.8:80 # 转发的包还需要filter表FORWARD链放行 iptables -A FORWARD -p tcp -d 10.0.0.8 --dport 80 -j ACCEPT
注意DNAT只改了地址,包能不能真正到达目标还取决于FORWARD链是否放行,这是新手最容易忽略的地方。MASQUERADE是SNAT的特殊形式,出口IP不固定时它会自动读取当前网卡地址,家庭宽带或DHCP环境下特别实用。
五、排查规则的常用手段
规则不生效时,第一步用iptables -L -n -v查看每条规则的包计数和字节计数,看流量到底有没有命中你写的规则。第二步用iptables -t nat -L -n确认nat表内容,很多人只查filter表,忘了地址转换可能发生在别的表。第三步查看连接跟踪状态cat /proc/net/nf_conntrack,确认内核是否正确识别了连接状态。如果系统走的是nftables后端,再配合nft list ruleset看全局视图,排查firewalld和手动规则叠加造成的冲突。
理解了netfilter的钩子位置、四表五链的优先级、连接跟踪的状态匹配,再回头看iptables的每一条命令,你会发现它们都不是孤立的语法,而是对内核数据包处理路径的精确干预。这也是为什么老手排查网络问题总是先画数据包流向图——规则写在哪里,包就在哪里被处理,掌握了这个底层逻辑,Fedora上的防火墙管理就再也不会凭感觉了。