3. firewalld架构与核心概念

firewalld 是 RHEL 7 及以后版本默认的动态防火墙管理工具,它取代了传统的 iptables service,核心价值在于“动态性”:修改规则时无需重启整个防火墙,也不会中断已建立的连接。要真正掌握 firewalld,不能只记几条 firewall-cmd 命令,而必须理解它的对象模型——zone、service、port、rich rule,以及 runtime 与 permanent 两套配置的关系。本节围绕这些概念展开,并给出可验证的操作示例。

一、firewalld 的整体架构

firewalld 本身并不是内核防火墙,它只是管理内核 netfilter 的前端。真正执行包过滤的是内核中的 nftables(RHEL 8/9)或 iptables(RHEL 7)子系统。firewalld 通过 D-Bus 对外提供接口,firewall-cmd 命令行、firewall-config 图形界面以及 NetworkManager 都通过 D-Bus 与 firewalld 守护进程通信。守护进程把配置翻译成 nftables/iptables 规则,写入内核。

firewalld 的配置分为两层:runtime(运行时)和 permanent(永久)。runtime 配置保存在内存中,立即生效,但重启 firewalld 或系统后丢失;permanent 配置保存在 /etc/firewalld/ 下的 XML 文件中,重启后仍然存在,但不会自动应用到当前运行状态。两者之间通过 --runtime-to-permanent 或 --permanent 加 --reload 进行同步。理解这一点是避免“命令执行成功但重启后失效”这类问题的关键。

firewalld 架构与配置层次 用户接口层 firewall-cmd firewall-config NetworkManager D-Bus API firewalld 守护进程 解析 zone / service / port / rich rule,生成规则 Runtime 配置(内存) 立即生效,重启丢失 firewall-cmd 默认操作对象 --runtime-to-permanent 可保存 Permanent 配置(磁盘) /etc/firewalld/ 下 XML 文件 重启后保留,需 reload 生效 --permanent + --reload 内核 netfilter(nftables / iptables) 实际执行包过滤、NAT、端口转发 核心对象 zone/service/port rich rule 精细控制

二、zone:信任级别的划分

zone 是 firewalld 最核心的概念,它代表一种“信任级别”,把网络接口或源地址划分到不同的信任区域中。每个 zone 内部维护自己的规则集合,决定哪些流量被允许、哪些被拒绝。RHEL 预定义了多个 zone,常用的有:

  • trusted:信任所有流量,几乎不做过滤,仅用于完全可信环境。
  • public:默认 zone,用于公共网络,只放行明确允许的服务。
  • work:工作环境,信任级别略高于 public。
  • home:家庭环境,信任级别更高。
  • internal:内部网络,信任级别较高。
  • external:外部网络,启用 masquerade(地址伪装),用于 NAT 出口。
  • dmz:隔离区,仅放行对外服务。
  • block:拒绝所有入站,仅允许本机主动发起的连接返回。
  • drop:丢弃所有入站包,不返回任何响应。

一个接口只能属于一个 zone,但一个 zone 可以包含多个接口。如果接口没有显式绑定 zone,则使用默认 zone(通常是 public)。查看当前默认 zone 和接口绑定关系:

firewall-cmd --get-default-zone
firewall-cmd --get-active-zones
firewall-cmd --zone=public --list-all

三、service 与 port:放行规则的基本单元

service 是预定义的一组端口和协议集合,例如 http 对应 TCP 80,https 对应 TCP 443,ssh 对应 TCP 22。使用 service 比直接写端口更清晰,也便于跨环境复用。firewalld 自带大量 service 定义,存放在 /usr/lib/firewalld/services/,自定义 service 放在 /etc/firewalld/services/。

port 则是直接指定端口和协议,适合没有预定义 service 的场景。例如放行 TCP 8080:

firewall-cmd --zone=public --add-port=8080/tcp --permanent
firewall-cmd --reload
firewall-cmd --zone=public --list-ports

注意:--permanent 写入磁盘但不立即生效,必须 --reload 才会加载到 runtime。如果希望立即生效且不丢失,可以先不加 --permanent 执行一次,再加 --permanent 执行一次,或者使用 --runtime-to-permanent 把当前 runtime 整体保存。

四、rich rule:精细化的规则表达

当 service 和 port 无法满足需求时,rich rule 提供了接近 iptables 的表达能力。它可以指定源地址、目标地址、端口、协议、日志、限速、连接跟踪等条件,并支持 accept、reject、drop、mark、log 等动作。rich rule 的语法结构为:

rule [family="ipv4|ipv6"]
  [source address="CIDR"|mac="MAC"]
  [destination address="CIDR"]
  [element]
  [action]

例如,只允许 192.168.10.0/24 网段访问 SSH,其他来源拒绝:

firewall-cmd --zone=public --add-rich-rule='
  rule family="ipv4"
  source address="192.168.10.0/24"
  service name="ssh" accept' --permanent
firewall-cmd --zone=public --add-rich-rule='
  rule family="ipv4"
  service name="ssh" reject' --permanent
firewall-cmd --reload

rich rule 按添加顺序匹配,先匹配到的规则生效。因此“允许特定来源”必须放在“拒绝所有”之前。这一点与 iptables 的规则顺序逻辑一致,是排障时最容易忽略的地方。

五、runtime 与 permanent 的同步策略

实际运维中,推荐两种工作方式:

  1. 先 runtime 验证,再 permanent 固化:不加 --permanent 执行命令,立即测试连通性;确认无误后执行 firewall-cmd --runtime-to-permanent,把当前 runtime 整体写入磁盘。
  2. 直接 permanent + reload:适合批量配置或脚本化部署,但 reload 会短暂重建规则链,可能影响已建立连接(取决于连接跟踪状态)。
不要混用两种方式而不检查状态。例如先加了 --permanent 但忘记 --reload,此时 --list-all 看到的是 runtime 状态,会误以为规则没生效;反之,只加了 runtime 而忘记保存,重启后规则全部丢失。

六、验证与排障要点

配置完成后,建议按以下顺序验证:

  • firewall-cmd --zone=public --list-all 查看当前 runtime 完整规则。
  • firewall-cmd --zone=public --list-all --permanent 查看磁盘上的永久规则。
  • firewall-cmd --get-active-zones 确认接口绑定的 zone 是否正确。
  • 从外部主机用 nc -zv 目标IP 端口 或 curl 测试实际连通性。
  • 必要时用 firewall-cmd --zone=public --query-port=8080/tcp 查询单条规则是否存在。

如果发现规则“看起来对但访问不通”,优先检查三件事:接口是否绑定了预期的 zone、rich rule 顺序是否被前面的 reject/drop 拦截、以及 permanent 与 runtime 是否一致。掌握 zone、service、port、rich rule 四个对象,以及 runtime/permanent 两层配置的同步关系,就掌握了 firewalld 的骨架,后续的 NAT、端口转发、直接规则等高级特性都建立在这个模型之上。