Linux 防火墙实战:用 firewalld 配置 External/Internal 区域,实现 NAT 内网共享上网

摘要
本文以一个真实的实验场景为背景,讲解如何在一台充当路由/网关角色的 Linux 主机(本文为 Server02)上通过 firewalld 配置外网接口和内网接口,并开启伪装(masquerade)实现 NAT,从而让内网主机(Server01)能够访问外网。文章以口语化、接近日常交流的方式呈现,包含配置命令、配置解析、实践示例与测试结果,并对代码模块和重要命令做详细讲解,帮助你在类似场景中快速复现并理解原理。
描述(场景说明)
假设你在一个小型办公室或实验室里,有两台主机:
- 
Server02:作为网关/防火墙主机(装了 Kylin / CentOS / RHEL 等支持 firewalld 的发行版),有两个网卡: - ens36:连接到外网(互联网或公司外网)
- ens160:连接到内网(192.168.10.0/24 之类的内部网段),负责和内网主机通信并为其提供上网能力
 
- 
Server01:内网主机,默认网关指向 Server02 的内网接口 ens160,没有直接路由到外网的能力。
目标是:
- 将 Server02 的外网接口 ens36设置为 firewalld 的external区域(该区域表示不信任外部连接),并启用伪装(masquerade),这样对来自内网的流量进行地址转换(SNAT)——把源地址改为ens36的 IP。
- 将 Server02 的内网接口 ens160设置为internal区域,默认允许较多来自内网的连接。
- 验证内网主机(Server01)是否能够通过 Server02 上网。
为什么要这样做?因为内网主机的私有地址(比如 192.168.x.x)不会被互联网路由。通过 NAT(伪装)把这些地址转换成外网 IP,就能让内网主机发起外网连接并接收响应。
题解答案(简要操作步骤)
查询接口当前所属的 zone:
firewall-cmd --get-zone-of-interface=ens36
firewall-cmd --get-zone-of-interface=ens160
将 ens36 加入 external 区域(永久):
firewall-cmd --permanent --zone=external --change-interface=ens36
将 ens160 加入 internal 区域(永久):
firewall-cmd --permanent --zone=internal --change-interface=ens160
在 external 区域启用伪装(masquerade):
firewall-cmd --permanent --zone=external --add-masquerade
firewall-cmd --reload
查询并确认设置生效:
firewall-cmd --zone=external --list-all
firewall-cmd --zone=internal --list-all
firewall-cmd --permanent --zone=external --query-masquerade
以上步骤是本文给出的“题解”部分的核心命令,下面会对每个命令、原理和示例输出作详细解释。
题解代码分析(命令详细解析与原理)
firewall-cmd --get-zone-of-interface=接口
用途:查看指定接口当前被分配到哪个 zone。很多时候 NetworkManager 会在接口激活时默认分配 public 或其他 zone,先确认当前状态能帮助我们判断是否需要修改。
示例:
[root@Server02 ~]# firewall-cmd --get-zone-of-interface=ens36
public
解析:输出 public 表示目前该接口被分配到 public 区域,可能不适合直接面向外网的信任与策略。我们希望把它放到 external 区域以便启用伪装并将其视为不可信的外部网络。
firewall-cmd --permanent --zone=external --change-interface=ens36
用途:把接口永久挂到指定 zone(这里是 external)。--permanent 表示写入到配置文件,需要 --reload 或 --complete-reload 后生效到运行时(不过有些 NetworkManager 提示会即时生效)。
示例输出说明:
The interface is under control of NetworkManager, setting zone to 'external'.
success
解析:这表示 NetworkManager 管理该接口,firewalld 已将该接口的 zone 设置为 external 并返回成功。后续 firewall-cmd --reload 会保证配置在下一次启动仍然有效。
注意事项:如果你使用的是系统网络配置工具(比如 NetworkManager、ifcfg 脚本等),也可以直接在这些工具里指定 zone。比如 NetworkManager 的 nmcli 可以做相同操作。
firewall-cmd --permanent --zone=external --add-masquerade
用途:为 external 区域开启 masquerade(伪装)。这实际在后端为 iptables/nftables 添加 NAT 规则(SNAT/POSTROUTING)——把来自被信任区(如 internal)的流量在出外网时修改源地址为外网接口地址。
为什么用 masquerade 而不是直接 SNAT?masquerade 更适合动态 IP(比如 PPPoE、DHCP 获得的公网 IP 会变动),firewalld 会自动使用出接口的当前 IP。而静态 SNAT 规则需要指定固定的外网 IP。
常见组合:把外网接口放到 external,启用 masquerade;把内网接口放到 internal(或 trusted),然后允许必要的转发和端口转发(如果需要做端口映射)。
firewall-cmd --reload 与 --zone=... --list-all
--reload 会把 --permanent 改动加载到运行时;--list-all 用于显示 zone 的当前配置,包含 interfaces、services、ports、masquerade 等。
示例:
[root@Server02 ~]# firewall-cmd --zone=external --list-all
external (active)target: defaulticmp-block-inversion: nointerfaces: ens36sources:services: sshports:protocols:masquerade: yes
解析:masquerade: yes 表示伪装已启用;services: ssh 说明该 zone 允许 ssh 服务(如果你远程管理网关,这一点非常重要)。
把内网接口放到 internal:
命令:
firewall-cmd --permanent --zone=internal --change-interface=ens160
firewall-cmd --reload
解析:internal 区域默认比 public 更信任内部网络。你可以根据需要对 internal 区域添加允许的服务(DNS、DHCP、HTTP 等),或保留默认设置。
使能 IP 转发(系统级设置,firewalld 之外)
除了上面 firewalld 的配置外,还必须在内核层面开启 IP 转发,否则 NAT 无法生效。查看与开启的方法:
查看当前状态:
sysctl net.ipv4.ip_forward
# 或
cat /proc/sys/net/ipv4/ip_forward
临时开启(重启后失效):
sysctl -w net.ipv4.ip_forward=1
永久开启(修改 /etc/sysctl.conf):
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p
解析:firewalld 添加了 NAT 规则,但内核必须允许转发包从内网接口转到外网接口,ip_forward=1 是必要条件。
如果需要做端口转发(DNAT),示例:
假设你希望把外网的 80 端口映射到内网某台 Web 服务器(192.168.10.20:80),可以使用:
firewall-cmd --permanent --zone=external --add-forward-port=port=80:proto=tcp:toaddr=192.168.10.20:toport=80
firewall-cmd --reload
解析:这会在外面接口上把到达 80 的连接转发到指定内网地址。注意同时需要在 internal 区域允许相应服务或策略(内网服务器可能需要允许来自 Server02 的流量)。
示例测试及结果
以下给出一个完整的演练流程(假设 Server02 的外网接口 ens36 的 IP 是 203.0.113.10,内网 ens160 的 IP 是 192.168.10.1,Server01 IP 为 192.168.10.20):
- 
在 Server02 执行: # 查看接口 zone firewall-cmd --get-zone-of-interface=ens36 firewall-cmd --get-zone-of-interface=ens160# 修改 zone firewall-cmd --permanent --zone=external --change-interface=ens36 firewall-cmd --permanent --zone=internal --change-interface=ens160# 启用 masquerade 并重载 firewall-cmd --permanent --zone=external --add-masquerade firewall-cmd --reload# 开启内核转发 sysctl -w net.ipv4.ip_forward=1 echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf sysctl -p# 查看外网 zone 配置 firewall-cmd --zone=external --list-all
- 
在 Server01 上设置网关为 Server02 的内网 IP(例子用 ip 命令临时设置): ip route replace default via 192.168.10.1 dev eth0 # 或修改 /etc/sysconfig/network-scripts/ifcfg-xxx 或 /etc/netplan/(视发行版而定)
- 
测试连通性: - 从 Server01 ping 8.8.8.8(测试是否能到达外网 IP)
- 从 Server01 curl http://ifconfig.me或curl https://ipinfo.io/ip(查看对方看到的源 IP,应该是 203.0.113.10)
 
测试结果示例(预期):
# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=54 time=30.2 ms# curl http://ifconfig.me  -> 返回 203.0.113.10
如果能看到外网 IP,说明 NAT 已经正常工作。
常见问题排查:
- 如果 ping 无法通过但 Server02 能连外网,检查 sysctl net.ipv4.ip_forward是否为 1。
- 检查防火墙规则:firewall-cmd --list-all-zones,看是否有阻断 FORWARD 的规则。
- 如果使用 nftables/iptables 后端,查看 iptables -t nat -L -n -v或nft list ruleset来调试 NAT 规则。
时间复杂度
这里不是算法题,但如果非要给出一个关于配置操作的“时间复杂度”类比:
- 执行单条 firewall-cmd命令的时间主要受系统负载和配置文件大小影响,可视为 O(1)(常数时间)。
- 整个配置流程包含固定数量的命令(查询、修改、重载),总体也是 O(1)。
因此,从工程角度看,该任务的时间复杂度是常数级别。
空间复杂度
配置不会占用明显的额外磁盘或内存空间,firewalld 的配置文件会在 /etc/firewalld/ 下写入少量文本,属于 O(1) 级别的空间使用。
总结
本文从一个具体案例入手,说明了如何将 Server02 的外网接口 ens36 加入 external 区域,并开启 masquerade 来实现 NAT,使内部主机能够通过 Server02 上网。文章重点覆盖了:
- firewalld 的接口与 zone 的绑定操作与解释;
- 为什么要启用 masquerade(适用于动态公网 IP);
- 必须在内核层面开启 IP 转发;
- 如何验证 NAT 是否生效以及常见排错方法;
- 如果需要端口映射(DNAT)应如何设置。
实践建议:在生产环境更改防火墙和 NAT 配置前,请先在测试环境验证,确保不会误断远程管理(例如 ssh)连接。对于长期可靠的公网服务,考虑把外网接口使用静态 IP 并在必要时使用更严格的 iptables/nftables 规则管理端口映射和访问控制。
