【Linux】网络安全管理:Netfilter、nftables 与 Firewalld | Redhat
本专栏文章持续更新,新增内容使用蓝色表示。
一、netfilter
Linux 内核提供了 netfilter 框架,用于实现网络流量操作功能,比如数据包过滤、网络地址转换(NAT)及端口转换等。该框架通过在内核网络协议栈中预设多个 hook 点,使内核模块能够在数据包经过不同处理阶段时与之交互。netfilter hook 作为一种内核例程,可拦截特定网络事件(如数据包到达网络接口),并触发相应的处理流程(例如执行防火墙规则)。防火墙的底层实现正是基于 netfilter,通过对数据包进行转发、过滤等操作来实现访问控制。
二、nftables
防火墙本质上可视为一套基于规则的白名单机制,用于明确允许或拒绝特定端口的访问。默认策略为“默认拒绝,显式允许”,只有在规则明确允许的情况下,相应流量才能通过。
nftables 是用户用来配置和管理的防火墙工具,具体的数据包拦截决策由其执行。它是构建于 netfilter 之上对数据包分类的框架,负责将防火墙规则应用于网络流量。在 RHEL 9 及更新版本中,nftables 已成为系统防火墙的核心组件,全面取代了之前使用的 iptables 框架。
2.1【了解】nftables 框架优势(相较于 iptables)
nftables 在可用性和规则集效率方面相比 iptables 有显著改进。例如,iptables 需要为不同协议编写独立规则(如分别使用 iptables 和 ip6tables 处理 IPv4 和 IPv6 流量),而 nftables 则可使用同一套规则同时处理 IPv4 和 IPv6 流量,语法统一且简洁。
此外,iptables 要求对各类网络协议使用不同的工具链,如 iptables、ip6tables、arptables 和 ebtables,而 nftables 仅通过单一的 nft 用户空间实用程序,即可统一配置和管理所有协议,大幅提升了操作的一致性和管理效率。
2.2【了解】防火墙规则迁移
使用 iptables-translate 和 ip6tables-translate 实用程序,将现有的 iptables 或 ip6tables 规则转换为对应的 nftables 规则配置,以简化从传统 iptables 框架向 nftables 框架的迁移过程。
2.3 内核的“钓鱼执法”
1)鱼塘与钓点(网络流量与 Hook 点)
整个鱼塘就是流经系统的所有网络数据包。
鱼塘边几个固定的最佳钓鱼位置就是内核网络栈中的 netfilter hook 点(如 NF_INET_PRE_ROUTING, NF_INET_LOCAL_IN 等)。
2)钓鱼者注册钓位(内核模块注册 Hook)
钓鱼者(如 nftables, iptables 等防火墙工具)想钓鱼,就必须先去塘主(内核)那里租用一个钓位(注册一个 hook 回调函数)。
一个钓位(hook 回调函数)上可以有多个钓鱼者(防火墙规则)排队(优先级),鱼来了会按顺序处理。
3)鱼上钩了(数据包到达 Hook 点)
一条鱼(网络数据包)游到了某个钓点(hook 点)。在这个点的所有钓鱼者(注册的回调函数)都有机会依次检查这条鱼。
4)钓鱼者判断并决定(防火墙规则处理)
每个钓鱼者(即一组防火墙规则)会根据自己手上的《钓鱼手册》(规则集)对鱼进行判断:
保护品种(如 SSH 端口) -> 放生(ACCEPT):允许其继续游向目的地(应用程序)。
有毒品种(如恶意攻击流量) -> 拒绝并扔掉(DROP):直接丢弃。注意:一旦这里返回 DROP,处理立即终止。
可食用品种(如 Web 流量) -> 收下(ACCEPT):允许通过。
观赏品种(需特殊处理) -> 修改(MASQUERADE/SNAT):给鱼换个颜色(做地址转换),然后放回鱼塘(转发出去)。
未知品种(如访问未开放的端口) -> 主动驱离(REJECT):扔掉鱼,同时向来源方向扔个石子(发送 TCP RST 或 ICMP 错误包)。
5)最终去向
鱼经过所有钓鱼者的检查和处理后,最终会被决定是 ACCEPT、DROP 还是 FORWARD。
三、firewalld
之前介绍的 netfilter 与 nftables 属于防火墙的底层技术框架,而在实际运维中通常用 firewalld 作为防火墙管理器,是一个配置工具。
firewalld 并非直接执行包过滤,而是作为 nftables 框架的前端配置工具,其底层通过调用 nft 命令或使用相关 API,将这些规则下发至内核中执行。所有数据包的过滤、转发等决策,最终仍由内核中的 nftables 通过 netfilter hook 完成。通过引入“区域”(Zone)和“服务”(Service)等易于理解的概念,简化了防火墙策略的管理。
补充:从 Linux 7 开始,系统服务(守护进程)的名称通常以后缀 d 标识。
firewalld 的核心管理机制是将网络流量划分到不同的区域(zone) 中,每个区域可独立配置防火墙规则。根据数据包源 IP 地址或传入网络接口等条件,流量将转入相应 zone (如 public、trusted),并应用该区域所定义的规则(允许的服务、端口等)。
firewalld 对每个进入系统的数据包执行以下判断流程:
若数据包的源 IP 地址已绑定至某个 zone,则直接应用该区域的规则;
若源 IP 未绑定至任何 zone,则使用接收接口所关联的 zone 规则;
若接口也未绑定 zone,则最终使用默认 zone(通常为 public);
系统默认将环回接口 lo 关联至 trusted zone,该区域通常允许所有流量。
绝大多数 zone 会放行与已开放端口、协议或预定义服务列表相匹配的流量,未匹配的流量通常将被拒绝。
3.1 预定义 zone
区域名称 | 宽松程度 | 默认允许的传入服务 | 特殊说明 |
---|---|---|---|
trusted | 最宽松 | 所有 | 完全信任 |
home | 较宽松 | ssh, mdns, ipp, samba, dhcpv6 | 用于家庭网络 |
internal | 较宽松 | ssh, mdns, ipp, samba, dhcpv6 | 同 home 区域 |
work | 中等 | ssh, ipp, dhcpv6 | 用于工作网络 |
public | 较严格 | ssh, dhcpv6 | 新接口的默认区域 |
external | 严格 | ssh | 对传出流量进行IP伪装(用于网关) |
dmz | 严格 | ssh | 用于隔离区服务器 |
block | 很严格 | 无(仅响应包) | 明确拒绝连接 |
drop | 最严格 | 无 | silently 丢弃包,不响应 |
3.2 预定义服务
服务名称 | 用途 | 协议与端口 |
---|---|---|
ssh | SSH 服务器 | 22/tcp |
dhcpv6-client | DHCPv6 客户端 | 546/udp (在 fe80::/64 网络) |
ipp-client | IPP 打印客户端 | 631/udp |
samba-client | Windows 文件和打印共享客户端 | 137/udp, 138/udp |
mdns | 多播 DNS 名称解析 | 5353/udp (发往 224.0.0.251 或 ff02::fb) |
firewall-cmd --get-services 可以列出这些预定义服务。
预定义服务的配置文件位于 /usr/lib/firewalld/services 中。
3.3 配置防火墙
firewall-cmd 命令是 firewalld 的命令行工具,几乎所有命令都作用于 runtime 配置,即更改之后立即生效。一般使用防火墙时都需要和特定的区域相关联,采用 --zone=ZONE 选项。
若要永久更改,可增加 --permanent 选项(不会立即生效),此时需要运行 firewall-cmd --reload 命令来激活设置,使得更改的参数都能够在内存刷新一下。它将读取当前的永久配置并将其作为新的 runtime 配置来应用。
示例:
# []的内容根据需要替换# 设置默认区域(定义新接口的默认策略)
firewall-cmd --set-default-zone=[目标区域]# 为指定区域定义规则
# 定义流量来源(允许来自特定IP段的流量使用此区域规则)
firewall-cmd --permanent --zone=[目标区域] --add-source=[源IP/掩码]
# 放行具体服务(在该区域允许某个服务)
firewall-cmd --permanent --zone=[目标区域] --add-service=[目标服务]# 应用永久更改
firewall-cmd --reload
3.4 防火墙常用命令
3.4.1 查看防火墙状态
systemctl status firewalld
firewall-cmd --state
3.4.2 临时启停防火墙
systemctl start firewalld # 启动
systemctl stop firewalld # 停止
3.4.3 永久启用/禁用防火墙
systemctl enable firewalld # 开机自启
systemctl disable firewalld # 禁用自启
3.4.4 开放和关闭端口
# 临时开放端口(重启后失效)
sudo firewall-cmd --add-port=80/tcp# 永久开放端口
sudo firewall-cmd --add-port=80/tcp --permanent# 临时关闭端口
sudo firewall-cmd --remove-port=80/tcp# 永久关闭端口
sudo firewall-cmd --remove-port=80/tcp --permanent# 开放端口范围
sudo firewall-cmd --add-port=8000-9000/tcp --permanent# 重新加载防火墙配置(使永久规则生效)
sudo firewall-cmd --reload
预告
【实验】SELinux 和 防火墙联合使用
如有问题或建议,欢迎在评论区中留言~