firewalld 防火墙详解:以firewall-cmd –zone=public –list-all的输出为例
本文以一台 Ubuntu 服务器上 firewall-cmd --zone=public --list-all 的实际输出为线索,逐行拆解 firewalld 的每一项配置,并穿插介绍其背后的概念、机制和常用操作。这样既能理解命令输出,也能掌握 firewalld 的整体工作方式。
先看我们的原始输出:
richard@ubuphy001:~$ sudo firewall-cmd --zone=public --list-all
public (default, active)
target: default
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces: enp1s0
sources:
services: dhcpv6-client ssh
ports:
protocols:
forward: yes
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
下面我们逐行分析,并在每一部分展开相关背景知识。
一、命令与输出结构
1.1 命令的含义
sudo firewall-cmd --zone=public --list-all
firewall-cmd:firewalld 的命令行客户端,用来查询和修改防火墙配置--zone=public:指定要操作/查看的区域为public--list-all:列出该区域当前运行时的全部配置sudo:修改防火墙需要 root 权限,虽然查询有时普通用户也能执行,但加上sudo更稳妥
如果加上 --permanent,则会显示永久配置而非运行时配置:
sudo firewall-cmd --zone=public --list-all --permanent
1.2 输出的整体结构
第一行 public (default, active) 是区域的“状态头”,包含三个信息:
- public:区域名称
- default:这是系统默认区域(
--get-default-zone会返回 public) - active:该区域当前处于激活状态,即有网络接口绑定在它上面
我们这台机器的默认区域是 public,而且 enp1s0 网卡正绑定在它上面,所以它是 active。
二、逐项拆解所输出的配置
2.1 target: default
target: default
含义:该区域对未匹配任何允许规则的入站数据包的最终处理方式。
本例解读:default 意味着——所有没有被 services、ports、rich rules 等明确放行的入站流量,都会被拒绝(REJECT) 。注意,名字叫“default”,但它的行为并不是“允许”,而是“默认拒绝”。
背景知识:target 的可选值有:
| 值 | 行为 |
|---|---|
default | 拒绝未匹配的包(发送拒绝响应) |
ACCEPT | 接受所有未匹配的包(trusted 区域用) |
%%REJECT%% | 以 firewalld 默认方式拒绝(block 区域用) |
DROP | 静默丢弃,不发送任何响应(drop 区域用) |
可以用以下命令修改区域的 target:
sudo firewall-cmd --permanent --zone=public --set-target=DROP
sudo firewall-cmd --reload
关键点:真正决定“放行什么”的,是 services、ports、rich rules 里明确列出的内容;target 只决定“其余怎么办”。
2.2 ingress-priority: 0 / egress-priority: 0
ingress-priority: 0
egress-priority: 0
含义:入站和出站数据包在本区域的处理优先级。
本例解读:都是 0,即普通优先级。数字越小越优先处理。
背景知识:优先级主要用于多个区域可能同时匹配一个包时(比如同时绑定了接口和源地址),决定哪个区域先被应用。一般默认 0 即可。
2.3 icmp-block-inversion: no
icmp-block-inversion: no
含义:ICMP 拦截的“反转开关”。
本例解读:no 表示正常模式——icmp-blocks 里列出的 ICMP 类型会被禁止。由于我们的 icmp-blocks 是空的,所以没有禁止任何 ICMP,包括 ping。
背景知识:如果设为 yes,则规则反转——icmp-blocks 列表里的类型反而被允许,其余全部拦截。这提供了一种 ICMP 白名单机制。
验证方法:从另一台机器 ping 这台服务器,应该是通的:
ping ubuphy001
如果想禁用 ping:
sudo firewall-cmd --zone=public --add-icmp-block=echo-request --permanent
sudo firewall-cmd --reload
2.4 interfaces: enp1s0
interfaces: enp1s0
含义:绑定到 public 区域的网络接口。
本例解读:enp1s0 是这台机器的主要网卡,它上面的入站流量全部套用 public 区域的规则。所以“默认拒绝、只放行 ssh 和 dhcpv6-client”这些规则,正是作用于这块网卡的。
背景知识:可以用命令查看接口和区域的绑定关系:
sudo firewall-cmd --get-active-zones
输出类似:
public
interfaces: enp1s0
也可以手动把接口移到别的区域:
sudo firewall-cmd --zone=trusted --change-interface=enp1s0 --permanent
sudo firewall-cmd --reload
2.5 sources: (空)
sources:
含义:按源 IP 地址/网段匹配该区域。
本例解读:为空,表示这个区域的匹配只靠网卡(enp1s0),不依赖源地址。任何从 enp1s0 进来的流量都会套用 public 区域规则,无论来源 IP 是什么。
背景知识:source 常用于“对特定来源的机器给予不同信任级别”。例如把某台内网机器划到 trusted:
sudo firewall-cmd --permanent --zone=trusted --add-source=192.168.1.100
sudo firewall-cmd --reload
这样来自 192.168.1.100 的流量就直接享受 trusted 区域的宽松规则,而不用改网卡。
2.6 services: dhcpv6-client ssh
services: dhcpv6-client ssh
含义:允许入站的预定义服务。这是本配置中真正放行流量的核心项。
本例解读:只放行两个服务:
- ssh → TCP 22 端口,允许远程登录管理
- dhcpv6-client → 允许本机作为 IPv6 DHCP 客户端收发 DHCPv6 报文
除这两个服务(以及后续会看到的 ports/rich rules,都是空的)之外的入站流量,都会被 target=default 拒绝。
背景知识:服务是“端口 + 协议”的预定义组合,比直接写端口更清晰。可以查看某个服务的定义:
sudo firewall-cmd --info-service=ssh
输出会显示 ports: 22/tcp 等细节。也可以列出所有预定义服务:
sudo firewall-cmd --get-services
注意:dhcpv6-client 和 ssh 是 firewalld 默认区域里通常会预置的服务,所以这个配置基本是“开箱默认”状态。
SSH 的重要性:因为我们只放行了 ssh,所以远程登录不受影响;如果哪天误删了 ssh 服务又 reload,可能立刻失去远程连接(除非有带外管理)。修改 SSH 相关规则时要格外小心。
2.7 ports: (空)
ports:
含义:直接放行的端口(如 8080/tcp)。
本例解读:为空,表示没有额外开放任何端口。也就是说,除了 ssh(22) 和 dhcpv6 涉及的端口外,本机不对外提供其他服务。
背景知识:当服务预定义不满足需求时(比如跑了一个 Web 服务在 8080),就用 ports:
sudo firewall-cmd --zone=public --add-port=8080/tcp --permanent
sudo firewall-cmd --reload
支持单个端口和端口范围:
sudo firewall-cmd --add-port=5060-5062/udp --permanent
查看已放行端口:
sudo firewall-cmd --zone=public --list-ports
2.8 protocols: (空)
protocols:
含义:单独放行的协议(不是端口,而是 IP 层协议,如 gre、esp)。
本例解读:为空,没有单独放行任何协议。
背景知识:协议值可以是协议名(参考 /etc/protocols)或协议号。常用于 VPN、IPsec 等场景:
sudo firewall-cmd --add-protocol=gre --permanent
sudo firewall-cmd --add-protocol=esp --permanent
sudo firewall-cmd --reload
大多数普通服务器不需要动这一项。
2.9 forward: yes
forward: yes
含义:是否允许同一区域内网络接口之间的流量转发。
本例解读:yes。但注意——这台机器只绑定了一个接口 enp1s0 在 public 区域,所以“同区域内接口间转发”实际上没有对象可转。这一项对当前拓扑没有实际影响。
容易混淆的点:
forward: yes不等于“本机能当路由器转发跨区域流量”- 也不等于“能上外网”(那是 masquerade 的事)
- 跨区域转发由
policy或全局--get-forward设置控制
背景知识:如果这台机器有多个网卡同属一个区域,转发才真正起作用。默认情况下 firewalld 的转发策略是比较保守的。
2.10 masquerade: no
masquerade: no
含义:IP 地址伪装(NAT)是否开启。
本例解读:no,关闭。这台机器不会把内网流量的源地址替换成自己的公网地址,即它不做 NAT 出口,内网其他机器不能通过它共享上网。
背景知识:masquerade 仅支持 IPv4,开启后会隐式启用 IP 转发。典型场景是把一台双网卡机器当路由器/网关:
sudo firewall-cmd --zone=external --add-masquerade --permanent
sudo firewall-cmd --reload
配合 external 区域使用是常见做法。注意富规则里也能写 masquerade,并可用 source/destination 限定伪装范围。
2.11 forward-ports: (空)
forward-ports:
含义:端口转发(目的地址转换,DNAT)。
本例解读:为空,没有配置任何端口转发。
背景知识:用于把到达本机某端口的流量转发到本机其他端口或另一台主机,常用来把内网服务发布到公网。例如把公网 80 端口转到内网 192.168.1.10:8080:
sudo firewall-cmd --zone=public --add-forward-port=port=80:proto=tcp:toport=8080:toaddr=192.168.1.10 --permanent
sudo firewall-cmd --reload
和 masquerade 配合可实现完整的入站发布 + 出站 NAT。
2.12 source-ports: (空)
source-ports:
含义:按来源端口匹配的规则。
本例解读:为空,没有按源端口做限制。
背景知识:这一项用得较少,通常用于对“来自特定源端口的流量”做特殊处理,实际运维中较少见。
2.13 icmp-blocks: (空)
icmp-blocks:
含义:要拦截的 ICMP 消息类型列表。
本例解读:为空。配合前面的 icmp-block-inversion: no,表示不拦截任何 ICMP 类型,ping 是通的。
背景知识:常用的是拦截 echo-request 来禁用 ping:
sudo firewall-cmd --zone=public --add-icmp-block=echo-request --permanent
sudo firewall-cmd --reload
查看系统支持的 ICMP 类型:
sudo firewall-cmd --get-icmptypes
注意:完全禁用 ICMP 并不总是好主意——PMTU 发现等机制依赖 ICMP,可能导致网络异常。通常只禁 echo-request 即可。
2.14 rich rules: (空)
rich rules:
含义:自定义的复杂规则。
本例解读:为空,没有任何富规则。所以目前所有放行都来自 services 里的 ssh 和 dhcpv6-client,其余一律拒绝。
背景知识:富规则是 firewalld 最灵活的表达方式,支持源/目标地址、端口、协议、日志、审计、动作等组合。完整结构大致如下:
rule [family="ipv4|ipv6"] [priority="priority"]
[ source [NOT] [address="address"] [mac="mac-address"] [ipset="ipset"] ]
[ destination [NOT] address="address" ]
[ element ]
[ log [prefix="prefix text"] [level="log level"] [limit value="rate/duration"] ]
[ audit ]
[ action ]
一个实用例子——只允许来自 192.168.1.0/24 网段 SSH 登录:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" service name="ssh" accept'
sudo firewall-cmd --reload
优先级:富规则的 priority 范围是 -32768 到 32767,值越低越优先。负优先级在其它 firewalld 原语之前执行,正优先级在之后执行,0 则按动作放入相应链。
超时机制:添加富规则时可用 --timeout=timeval(如 --timeout=1h),规则到期自动删除,适合临时放行。
三、运行时配置 vs 永久配置
我们的输出是运行时配置(没加 --permanent)。理解这两者的区别非常关键。
3.1 运行时配置(Runtime)
- 当前实际生效的规则,直接作用于内核
- 不指定
--permanent的修改只影响运行时 - 服务停止、重载(reload)后丢失
- firewalld 启动时,永久配置会加载为运行时配置
3.2 永久配置(Permanent)
- 存储在
/etc/firewalld/zones/下的 XML 文件里 - 系统启动或
--reload时被加载为新的运行时配置 - 单独用
--permanent修改不会立刻生效
3.3 两者关系与操作
# 查看永久配置,和运行时对比
sudo firewall-cmd --zone=public --list-all --permanent
# 把当前运行时配置保存为永久配置
sudo firewall-cmd --runtime-to-permanent
# 用永久配置覆盖运行时配置(未保存的临时修改会丢失)
sudo firewall-cmd --reload
典型工作流:先在运行时测试规则,确认无误后用 --runtime-to-permanent 保存。这样即使测试出错,reload 或重启就能恢复。
容易踩的坑:只加了 --permanent 却忘了 --reload,规则不会生效;反过来,只改运行时没保存,重启后就没了。
四、从我的配置得出的结论
综合以上逐项分析,这台 ubuphy001 的防火墙状态可以总结为:
- 网卡 enp1s0 绑定在 public 区域,套用 public 规则
- 默认拒绝所有未明确允许的入站流量(target: default)
- 只放行 SSH(22/tcp)和 DHCPv6 客户端两个服务
- 没有开放任何额外端口、协议、源端口
- 没有配置任何端口转发、NAT、富规则
- 没有拦截任何 ICMP,ping 是通的
- 本机不做 NAT 出口(masquerade: no),也不是路由器
这是一个非常干净、保守、接近默认的配置。作为一台通过 SSH 管理的物理服务器,这个状态是合理且安全的:能远程登录、能获取 IPv6 地址、其余一概拒绝。
五、常用操作命令速查
5.1 服务管理
systemctl start firewalld # 启动
systemctl enable firewalld # 开机自启
systemctl status firewalld # 查看状态
firewall-cmd --state # 守护进程是否活跃
firewall-cmd --reload # 重载(保留连接,推荐)
firewall-cmd --complete-reload # 完全重载(丢失连接,慎用)
5.2 区域管理
firewall-cmd --get-zones # 所有可用区域
firewall-cmd --get-default-zone # 默认区域
firewall-cmd --set-default-zone=work # 设置默认区域
firewall-cmd --get-active-zones # 查看激活区域及接口
firewall-cmd --zone=public --list-all # 查看区域运行时配置
firewall-cmd --zone=public --list-all --permanent # 查看永久配置
5.3 服务与端口
firewall-cmd --add-service=http # 运行时加服务
firewall-cmd --permanent --add-service=http # 永久加服务
firewall-cmd --add-port=8080/tcp # 运行时加端口
firewall-cmd --permanent --add-port=8080/tcp # 永久加端口
firewall-cmd --permanent --remove-service=http # 删除服务
firewall-cmd --permanent --remove-port=8080/tcp # 删除端口
firewall-cmd --list-services # 已放行服务
firewall-cmd --list-ports # 已放行端口
5.4 高级操作
# 禁用 ping
firewall-cmd --zone=public --add-icmp-block=echo-request --permanent
# 启用 IP 伪装(NAT)
firewall-cmd --zone=external --add-masquerade --permanent
# 保存运行时配置为永久
firewall-cmd --runtime-to-permanent
# 查看接口绑定
firewall-cmd --get-active-zones
结语
回到最初的那条命令,你现在应该能完整读懂它的每一行含义了:
public (default, active)→ 默认且激活的区域target: default→ 未匹配的入站包一律拒绝interfaces: enp1s0→ 规则作用于这块网卡services: dhcpv6-client ssh→ 只放行这两个服务- 其余为空或 no → 没有额外开放、没有 NAT、没有 ICMP 拦截、没有富规则
firewalld 通过区域抽象、运行时与永久配置分离、以及富规则等机制,在保持灵活性的同时降低了防火墙管理的复杂性。理解每一项配置的真实含义,才能在需要时准确、安全地修改规则——尤其是当你在远程管理一台只能靠 SSH 登录的服务器时。