Red Hat Training

A Red Hat training course is available for RHEL 8

第 46 章 使用和配置 firewalld

防火墙是保护机器不受来自外部的、不需要的网络数据的一种方式。它允许用户通过定义一组防火墙规则 来控制主机上的入站网络流量。这些规则用于对进入的流量进行排序,并可以阻断或允许流量。

firewalld 是一个防火墙服务守护进程,它为使用 D-Bus 接口提供动态可定制主机防火墙的防火墙服务守护进程。如果是动态的,它可在每次修改规则时启用、修改和删除规则,而不需要在每次修改规则时重启防火墙守护进程。

firewalld 使用区(zone)和服务(service)的概念来简化流量管理。zones 是预定义的规则集。网络接口和源可以分配给区。允许的流量取决于您计算机连接到的网络,并分配了这个网络的安全级别。防火墙服务是预定义的规则,覆盖了允许特定服务进入流量的所有必要设置,并在区中应用。

服务使用一个或多个端口或地址进行网络通信。防火墙会根据端口过滤通讯。要允许服务的网络流量,必须打开其端口。firewalld 阻断未明确设置为打开的端口上的所有流量。一些区(如可信区)默认允许所有流量。

请注意,带有 nftables 后端的 firewalld 不支持使用 --direct 选项将自定义 nftables 规则传递给 firewalld

46.1. 开始使用 firewalld

46.1.1. 使用 firewalld、nftables 或者 iptables 时

以下是您应该使用以下工具之一的概述:

  • firewalld: 在简单防火墙用例中使用 firewalld 工具。该工具非常容易使用,并涵盖这些场景的典型用例。
  • nftables: 使用 nftables 实用程序设置复杂和性能的关键防火墙,比如为整个网络设置。
  • iptables:Red Hat Enterprise Linux 8 中的 iptables 工具程序使用 nf_tables 内核 API 而不是 legacy 后端。nf_tables API 提供向后兼容性,使用 iptables 命令的脚本仍然可用于 Red Hat Enterprise Linux 8。对于新的防火墙脚本,红帽建议使用 nftables
重要

要避免不同的防火墙服务相互影响,在 RHEL 主机中只有一个服务,并禁用其他服务。

46.1.2. Zones

firewalld 可以用来根据用户决定放置在那个网络中的接口和流量级别的信任级别将网络划分为不同的区。一个连接只能是一个区的一部分,但一个区可以被用来进行很多网络连接。

NetworkManager 通知接口区的 firewalld。您可以为接口分配区:

  • NetworkManager
  • firewall-config 工具
  • firewall-cmd 命令行工具
  • RHEL web 控制台

后三个只能编辑正确的 NetworkManager 配置文件。如果您使用 web 控制台 firewall-cmdfirewall-config 更改接口区域,则请求会转发到 NetworkManager 且不由 ⁠firewalld 处理。

预定义区域存储在 /usr/lib/firewalld/zones/ 目录中,并可立即应用于任意可用的网络接口。只有在修改后,这些文件才会复制到 /etc/firewalld/zones/ 目录中。预定义区的默认设置如下:

block
任何传入的网络连接都会被拒绝,并会拒绝 IPv4 的 icmp-host-prohibited(用于 IPv6 )和 icmp6-adm-prohibited。只有从系统启动的网络连接才能进行。
dmz
对于您的非企业化区里的计算机来说,这些计算机可以被公开访问,且有限访问您的内部网络。只接受所选的入站连接。
drop
所有传入的网络数据包都会丢失,没有任何通知。只有外发网络连接也是可行的。
external
适用于启用了伪装的外部网络,特别是路由器。您不信任网络中的其他计算机不会损害您的计算机。只接受所选的入站连接。
home
用于家用,因为您可以信任其他计算机。只接受所选的入站连接。
internal
当您主要信任网络中的其他计算机时,供内部网络使用。只接受所选的入站连接。
public
可用于您不信任网络中其他计算机的公共区域。只接受所选的入站连接。
trusted
所有网络连接都被接受。
work
可用于您主要信任网络中其他计算机的工作。只接受所选的入站连接。

这些区中的一个被设置为 default 区。当接口连接添加到 NetworkManager 时,它们会被分配给默认区。安装时,firewalld 的默认区设置为 public 区。默认区可以被修改。

注意

网络区名称应该自我解释,并允许用户迅速做出合理的决定。要避免安全问题,请查看默认区配置并根据您的需要和风险禁用任何不必要的服务。

其它资源

  • firewalld.zone(5) man page。

46.1.3. 预定义的服务

服务可以是本地端口、协议、源端口和目的地列表,并在启用了服务时自动载入防火墙帮助程序模块列表。使用服务可节省用户时间,因为它们可以完成一些任务,如打开端口、定义协议、启用数据包转发等等,而不必在另外的步骤中设置所有任务。

服务配置选项和通用文件信息请参考 firewalld.service(5) man page。服务通过单独的 XML 配置文件指定,这些文件使用以下格式命名: service-name.xml。协议名称优先于 firewalld 中的服务或者应用程序名称。

可使用图形 firewall-config 工具、firewall-cmdfirewall-offline-cmd添加和删除服务。

另外,您也可以编辑 /etc/firewalld/services/ 目录中的 XML 文件。如果用户没有添加或更改服务,则在 /etc/firewalld/services/ 中没有找到对应的 XML 文件。如果要添加或更改服务,/usr/lib/firewalld/services/ 目录中的文件可作为模板使用。

其它资源

  • firewalld.service(5) man page

46.2. 查看当前状态和设置 firewalld

46.2.1. 查看当前状态 firewalld

防火墙服务 firewalld 被默认安装在系统中。使用 firewalld CLI 界面检查该服务是否正在运行。

流程

  1. 查看服务的状态:

    # firewall-cmd --state
  2. 有关服务状态的更多信息,请使用 systemctl status 子命令:

    # systemctl status firewalld
    firewalld.service - firewalld - dynamic firewall daemon
       Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor pr
       Active: active (running) since Mon 2017-12-18 16:05:15 CET; 50min ago
         Docs: man:firewalld(1)
     Main PID: 705 (firewalld)
        Tasks: 2 (limit: 4915)
       CGroup: /system.slice/firewalld.service
               └─705 /usr/bin/python3 -Es /usr/sbin/firewalld --nofork --nopid

其它资源

在尝试编辑设置前,了解 firewalld 是如何设置的以及哪些规则被强制实施非常重要。要显示防火墙设置,以 root 用户身份使用 firewall-cmd --list-all

46.2.2. 使用 GUI 查看允许的服务

要使用图形化的 firewall-config 工具查看服务列表,请按 Super 键进入" 活动概览",输入 firewall,然后按 Enter 键。firewall-config 工具会出现。现在您可以在 Services 标签页中查看服务列表。

您可以使用命令行启动图形防火墙配置工具。

流程

  • 使用命令行启动图形防火墙配置工具:

    $ firewall-config

Firewall Configuration 窗口将打开。请注意,这个命令可以以普通用户身份运行,但偶尔会提示您输入管理员密码。

46.2.3. 使用 CLI 查看 firewalld 设置

使用 CLI 客户端可能会对当前防火墙设置有不同的视图。--list-all 选项显示 firewalld 设置的完整概述。

firewalld 使用 zone 管理流量。如果 --zone 选项没有指定区,该命令将在分配给活跃网络接口和连接的默认区里有效。

流程

  • 要列出默认区的所有相关信息:

    # firewall-cmd --list-all
    public
      target: default
      icmp-block-inversion: no
      interfaces:
      sources:
      services: ssh dhcpv6-client
      ports:
      protocols:
      masquerade: no
      forward-ports:
      source-ports:
      icmp-blocks:
      rich rules:
  • 要指定显示设置的区域,在 firewall-cmd --list-all 命令中添加 --zone=zone-name 参数,例如:

    # firewall-cmd --list-all --zone=home
    home
      target: default
      icmp-block-inversion: no
      interfaces:
      sources:
      services: ssh mdns samba-client dhcpv6-client
    ... [trimmed for clarity]
  • 要查看特定信息(如服务或端口)的设置,请使用特定选项。请查看 firewalld 手册页或使用命令帮助获得选项列表:

    # firewall-cmd --help
  • 查看当前区中允许哪些服务:

    # firewall-cmd --list-services
    ssh dhcpv6-client
注意

使用 CLI 工具列出某个子部分的设置有时会比较困难。例如,允许 SSH 服务, firewalld 为该服务打开所需的端口(22)。之后,如果您列出允许的服务,列表会显示 SSH 服务,但如果您列出了开放端口,则不会显示任何服务。因此,建议您使用 --list-all 选项确定您收到完整信息。

46.3. 使用 firewalld

46.3.1. 使用 CLI 禁用紧急事件的所有流量

在紧急情况下,如系统攻击,可以禁用所有网络流量并关闭攻击者。

流程

  1. 要立即禁用网络流量,请切换 panic 模式:

    # firewall-cmd --panic-on
    重要

    启用 panic 模式可停止所有网络流量。因此,它应只在对机器有物理访问权限或者使用串口控制台登录时才使用。

  2. 关闭 panic 模式会使防火墙恢复到其永久设置。要关闭 panic 模式,请输入:

    # firewall-cmd --panic-off

验证

  • 要查看是否打开或关闭 panic 模式,请使用:

    # firewall-cmd --query-panic

46.3.2. 使用 CLI 控制预定义服务的流量

控制流量的最简单方法是在 firewalld 中添加预定义服务。这会打开所有必需的端口并根据 服务定义文件 修改其他设置。

流程

  1. 检查该服务是否还未被允许:

    # firewall-cmd --list-services
    ssh dhcpv6-client
  2. 列出所有预定义的服务:

    # firewall-cmd --get-services
    RH-Satellite-6 amanda-client amanda-k5-client bacula bacula-client bitcoin bitcoin-rpc bitcoin-testnet bitcoin-testnet-rpc ceph ceph-mon cfengine condor-collector ctdb dhcp dhcpv6 dhcpv6-client dns docker-registry ...
    [trimmed for clarity]
  3. 在允许的服务中添加服务:

    # firewall-cmd --add-service=<service-name>
  4. 使新设置持久:

    # firewall-cmd --runtime-to-permanent

46.3.3. 通过 GUI,使用预定义服务控制流量

这个步骤描述了如何使用图形用户界面控制预定义服务的网络流量。

流程

  1. 启用或禁用预定义或自定义服务:

    1. 启动 firewall-config 工具并选择要配置的服务的网络区。
    2. 选择 Services 标签。
    3. 选择您要信任的每种服务类型的复选框,或者清除要阻断服务的复选框。
  2. 编辑服务:

    1. 启动 firewall-config 工具。
    2. 从标记的 Configuration 菜单中选择 Permanent。其它图标和菜单按钮会出现在服务窗口底部。
    3. 选择您要配置的服务。

PortsProtocolsSource Port 标签页启用了为所选服务启用、更改和删除端口、协议和源端口。模块标签是用来配置 Netfilter helper 模块。Destination 标签允许将流量限制到特定的目标地址和互联网协议(IPv4IPv6)。

注意

Runtime 模式中无法更改服务设置。

46.3.4. 添加新服务

可使用图形化的 firewall-config 工具 firewall-cmdfirewall-offline-cmd添加和删除服务。或者,您可以编辑 /etc/firewalld/services/ 中的 XML 文件。如果用户没有添加或更改服务,则在 /etc/firewalld/services/ 中没有找到对应的 XML 文件。如果要添加或更改服务,/usr/lib/firewalld/services/ 文件可作为模板使用。

注意

服务名称必须是字母数字,以及 _(下划线)和 -(横线)字符。

流程

要在终端中添加新服务,请使用 firewall-cmdfirewall-offline-cmd (如果未激活 firewalld)。

  1. 运行以下命令以添加新和空服务:

    $ firewall-cmd --new-service=service-name --permanent
  2. 要使用本地文件添加新服务,请使用以下命令:

    $ firewall-cmd --new-service-from-file=service-name.xml --permanent

    您可以使用附加 --name=service-name 选项更改服务名称。

  3. 更改服务设置后,就会将服务更新副本放入 /etc/firewalld/services/ 中。

    作为 root,您可以输入以下命令手动复制服务:

    # cp /usr/lib/firewalld/services/service-name.xml /etc/firewalld/services/service-name.xml

firewalld 第一次从 /usr/lib/firewalld/services 加载文件。如果文件放在 /etc/firewalld/services 中,且它们有效,就会覆盖 /usr/lib/firewalld/services 中匹配的文件。一旦删除了 /etc/firewalld/services 中的匹配文件,或者要求 firewalld 加载服务的默认值,则将使用 /usr/lib/firewalld/services 中的覆盖文件。这只适用于永久性环境。要在运行时环境中获取这些回退,则需要重新载入。

46.3.5. 使用 GUI 打开端口

允许通过防火墙到特定端口的流量:

  1. 启动 firewall-config 工具并选择要更改的网络区。
  2. 选择 Ports 标签并点击右侧的添加按钮。Port and Protocol 窗口将打开。
  3. 输入要允许的端口号或者端口范围。
  4. 从列表中选择 tcpudp

46.3.6. 使用 GUI 控制协议的流量

使用特定的协议允许通过防火墙的流量:

  1. 启动 firewall-config 工具并选择要更改的网络区。
  2. 选择 Protocols 标签并点击右首的 Add 按钮。Protocol 窗口将打开。
  3. 您可以从列表中选择一个协议,也可以选择 Other Protocol 复选框并在字段中输入协议。

46.3.7. 使用 GUI 打开源端口

允许通过防火墙的流量来自特定端口:

  1. 启动 firewall-config 工具并选择要更改的网络区。
  2. 选择 Source Port 标签并点击右首的 Add 按钮。Source Port 窗口将打开。
  3. 输入要允许的端口号或者端口范围。从列表中选择 tcpudp

46.4. 使用 CLI 控制端口

端口是可让操作系统接收和区分网络流量并将其转发到系统服务的逻辑设备。它们通常由侦听端口的守护进程来表示,它会等待到达这个端口的任何流量。

通常,系统服务侦听为它们保留的标准端口。例如,httpd 守护进程侦听端口 80。但默认情况下,系统管理员会将守护进程配置为在不同端口上侦听以便增强安全性或出于其他原因。

46.4.1. 打开端口

通过打开端口,系统可从外部访问,这代表了安全风险。通常,让端口保持关闭,且只在某些服务需要时才打开。

流程

要获得当前区的打开端口列表:

  1. 列出所有允许的端口:

    # firewall-cmd --list-ports
  2. 在允许的端口中添加一个端口,以便为入站流量打开这个端口:

    # firewall-cmd --add-port=port-number/port-type

    端口类型可以是 tcpudpsctpdccp。这个类型必须与网络通信的类型匹配。

  3. 使新设置具有持久性:

    # firewall-cmd --runtime-to-permanent

    端口类型可以是 tcpudpsctpdccp。这个类型必须与网络通信的类型匹配。

46.4.2. 关闭端口

当不再需要开放端口时,在 firewalld中闭该端口。强烈建议您尽快关闭所有不必要的端口,因为端口处于打开状态会存在安全隐患。

流程

要关闭某个端口,请将其从允许的端口列表中删除:

  1. 列出所有允许的端口:

    # firewall-cmd --list-ports
    警告

    这个命令只为您提供已打开作为端口的端口列表。您将无法看到作为服务打开的任何打开端口。因此,您应该考虑使用 --list-all 选项而不是使用 --list-ports

  2. 从允许的端口中删除端口,以便对传入的流量关闭:

    # firewall-cmd --remove-port=port-number/port-type
  3. 使新设置具有持久性:

    # firewall-cmd --runtime-to-permanent

46.5. 使用 firewalld 区

zones 代表一种更透明管理传入流量的概念。这些区域连接到联网接口或者分配一系列源地址。您可以独立为每个区管理防火墙规则,这样就可以定义复杂的防火墙设置并将其应用到流量。

46.5.1. 列出区域

这个步骤描述了如何使用命令行列出区。

流程

  1. 查看系统中有哪些可用区:

    # firewall-cmd --get-zones

    firewall-cmd --get-zones 命令显示系统中所有可用的区域,但不显示具体区的详情。

  2. 查看所有区的详细信息:

    # firewall-cmd --list-all-zones
  3. 查看特定区的详细信息:

    # firewall-cmd --zone=zone-name --list-all

46.5.2. 更改特定区的 firewalld 设置

使用 cli 和 Controlling 端口控制预定义服务的流量 解释了如何在当前工作区范围内添加服务或修改端口。有时,需要在不同区内设置规则。

流程

  • 要在不同的区中工作,使用 --zone=zone-name 选项。例如,允许在区 public 中使用 SSH 服务:

    # firewall-cmd --add-service=ssh --zone=public

46.5.3. 更改默认区

系统管理员在其配置文件中为网络接口分配区域。如果接口没有被分配给指定区,它将被分配给默认区。每次重启 firewalld 服务后, firewalld 加载默认区的设置并使其活跃。

流程

设置默认区:

  1. 显示当前的默认区:

    # firewall-cmd --get-default-zone
  2. 设置新的默认区:

    # firewall-cmd --set-default-zone zone-name
    注意

    在此流程后,设置是一个永久设置,即使没有 --permanent 选项。

46.5.4. 将网络接口分配给区

可以为不同区定义不同的规则集,然后通过更改所使用的接口的区来快速改变设置。使用多个接口,可以为每个具体区设置一个区来区分通过它们的网络流量。

流程

要将区分配给特定的接口:

  1. 列出活跃区以及分配给它们的接口:

    # firewall-cmd --get-active-zones
  2. 为不同的区分配接口:

    # firewall-cmd --zone=zone_name --change-interface=interface_name --permanent

46.5.5. 使用 nmcli 为连接分配区域

这个步骤描述了如何使用 nmcli 工具在 NetworkManager 连接中添加 firewalld 区。

流程

  1. NetworkManager 连接配置集分配区域:

    # nmcli connection modify profile connection.zone zone_name
  2. 重新加载连接:

    # nmcli connection up profile

46.5.6. 在 ifcfg 文件中手动将区分配给网络连接

当连接由 网络管理器(NetworkManager)管理时,必须了解它使用的区域。为每个网络连接指定区域,根据计算机有可移植设备的位置提供各种防火墙设置的灵活性。因此,可以为不同的位置(如公司或家)指定区域和设置。

流程

  • 要为连接设置区,编辑 /etc/sysconfig/network-scripts/ifcfg-connection_name 文件并添加为这个连接分配区的行:

    ZONE=zone_name

46.5.7. 创建一个新区

要使用自定义区,创建一个新的区并使用它像预定义区一样。新区需要 --permanent 选项,否则命令无法正常工作。

流程

  1. 创建一个新区:

    # firewall-cmd --new-zone=zone-name
  2. 检查是否在您的永久设置中添加了新的区:

    # firewall-cmd --get-zones
  3. 使新设置具有持久性:

    # firewall-cmd --runtime-to-permanent

46.5.8. 区配置文件

区也可以通过区配置文件创建。如果您需要创建新区,但想从不同区重复使用设置,这种方法就很有用了。

firewalld 区配置文件包含区的信息。这些区描述、服务、端口、协议、icmp-blocks、masquerade、forward-ports 和丰富的语言规则采用 XML 文件格式。文件名必须是 zone-name.xml,其中 zone-name 的长度限制为 17 个字符。区配置文件位于 /usr/lib/firewalld/zones//etc/firewalld/zones/ 目录中。

以下示例显示了允许一个服务(SSH)和一个端口范围的配置,适用于 TCPUDP 协议:

<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>My Zone</short>
  <description>Here you can describe the characteristic features of the zone.</description>
  <service name="ssh"/>
  <port protocol="udp" port="1025-65535"/>
  <port protocol="tcp" port="1025-65535"/>
</zone>

要更改那个区的设置,请添加或者删除相关的部分来添加端口、转发端口、服务等等。

其它资源

  • 如需更多信息,请参阅 firewalld.zone man page。

46.5.9. 使用区目标设定传入流量的默认行为

对于每个区,您可以设置一种处理尚未进一步指定的传入流量的默认行为。这种行为是通过设置区目标来定义的。有四个选项 - defaultACCEPTREJECTDROP。通过将目标设置为 ACCEPT,您接受除特定规则禁用的数据包外的所有传入的数据包。如果将目标设置为 REJECTDROP,您将禁用所有传入的数据包,除非您在特定规则中允许的数据包。拒绝数据包时,会通知源机器,但丢弃数据包时不会发送任何信息。

流程

为区设置目标:

  1. 列出特定区的信息以查看默认目标:

    $ firewall-cmd --zone=zone-name --list-all
  2. 在区中设置一个新目标:

    # firewall-cmd --permanent --zone=zone-name --set-target=<default|ACCEPT|REJECT|DROP>

46.6. 根据源使用区管理传入流量

46.6.1. 根据源使用区管理传入流量

您可以使用区管理传入的流量,根据其源管理传入的流量。这可让您对进入的流量进行排序,并将其路由到不同的区,以允许或禁止该流量可访问的服务。

如果您给区添加一个源,区就会成为活跃的,来自该源的所有进入流量都会被定向到它。您可以为每个区指定不同的设置,这些设置相应地应用于来自给定源的网络流量。即使只有一个网络接口,您可以使用更多区域。

46.6.2. 添加源

要将传入的流量路由到特定源,请将源添加到那个区。源可以是一个使用 CIDR 格式的 IP 地址或 IP 掩码。

注意

如果您添加多个带有重叠网络范围的区域,则根据区名称排序,且只考虑第一个区。

  • 在当前区中设置源:

    # firewall-cmd --add-source=<source>
  • 要为特定区设置源 IP 地址:

    # firewall-cmd --zone=zone-name --add-source=<source>

以下流程将在 trusted 区中允许来自 192.168.2.15 的流量:

流程

  1. 列出所有可用区:

    # firewall-cmd --get-zones
  2. 将源 IP 添加到持久性模式的信任区中:

    # firewall-cmd --zone=trusted --add-source=192.168.2.15
  3. 使新设置具有持久性:

    # firewall-cmd --runtime-to-permanent

46.6.3. 删除源

从区中删除源会关闭来自它的网络流量。

流程

  1. 列出所需区的允许源:

    # firewall-cmd --zone=zone-name --list-sources
  2. 从区永久删除源:

    # firewall-cmd --zone=zone-name --remove-source=<source>
  3. 使新设置具有持久性:

    # firewall-cmd --runtime-to-permanent

46.6.4. 添加源端口

要启用根据原始端口对流量排序,使用 --add-source-port 选项指定源端口。您还可以将此选项与 --add-source 选项合并,将流量限制为特定 IP 地址或 IP 范围。

流程

  • 添加源端口:

    # firewall-cmd --zone=zone-name --add-source-port=<port-name>/<tcp|udp|sctp|dccp>

46.6.5. 删除源端口

通过删除源端口,您可以根据原始端口禁用对流量排序。

流程

  • 要删除源端口:

    # firewall-cmd --zone=zone-name --remove-source-port=<port-name>/<tcp|udp|sctp|dccp>

46.6.6. 使用区和源来允许一个服务只适用于一个特定的域

要允许特定网络的流量在机器上使用服务,请使用区和源。以下流程只允许来自 192.0.2.0/24 网络的 HTTP 流量,同时阻断任何其他流量。

警告

当您配置这种情况时,请使用具有 default 目标的区域。使用将目标设置为 ACCEPT 的区域会存在安全隐患,因为对于来自 192.0.2.0/24 的流量,所有网络连接都会被接受。

流程

  1. 列出所有可用区:

    # firewall-cmd --get-zones
    block dmz drop external home internal public trusted work
  2. 将 IP 范围添加到 internal 区域,将来自源的网络流量路由到区:

    # firewall-cmd --zone=internal --add-source=192.0.2.0/24
  3. internal 区中添加 http 服务:

    # firewall-cmd --zone=internal --add-service=http
  4. 使新设置具有持久性:

    # firewall-cmd --runtime-to-permanent

验证

  • 检查 internal 区是否活跃,且该服务是否允许。

    # firewall-cmd --zone=internal --list-all
    internal (active)
      target: default
      icmp-block-inversion: no
      interfaces:
      sources: 192.0.2.0/24
      services: cockpit dhcpv6-client mdns samba-client ssh http
      ...

其它资源

  • 有关区的详情,请参考 firewalld.zones(5) man page。

46.7. 使用 firewalld 配置 NAT

使用 firewalld,您可以配置以下网络地址转换(NAT)类型:

  • 伪装
  • 源 NAT(SNAT)
  • 目标 NAT(DNAT)
  • 重定向

46.7.1. 不同的 NAT 类型: masquerading、source NAT、destination NAT 和 redirect

这些是不同的网络地址转换(NAT)类型:

伪装和源 NAT(SNAT)

使用以上 NAT 类型之一更改数据包的源 IP 地址。例如:互联网服务提供商不会路由私有 IP 范围,如 10.0.0.0/8。如果您在网络中使用私有 IP 范围,并且用户可以访问互联网中的服务器,请将这些范围内的数据包源 IP 地址映射到一个公共 IP 地址。

伪装和 SNAT 都非常相似。不同之处是:

  • 伪装自动使用传出接口的 IP 地址。因此,如果传出接口使用了动态 IP 地址,则使用伪装。
  • SNAT 将数据包的源 IP 地址设置为指定的 IP 地址,且不会动态查找传出接口的 IP 地址。因此,SNAT 要比伪装更快。如果传出接口使用了固定 IP 地址,则使用 SNAT。
目标 NAT(DNAT)
使用此 NAT 类型重写传入数据包的目标地址和端口。例如,如果您的网页服务器使用来自私有 IP 范围内的 IP 地址,因此无法直接从互联网访问,您可以在路由器上设置 DNAT 规则来重定向进入该服务器的流量。
重定向
这个类型是 IDT 的特殊示例,它根据链 hook 将数据包重定向到本地机器。例如,如果服务在与标准端口不同的端口中运行,您可以将标准端口传入的流量重定向到这个特定端口。

46.7.2. 配置 IP 地址伪装

以下流程描述了如何在系统中启用 IP 伪装。IP 伪装会在访问互联网时隐藏网关后面的独立机器。

流程

  1. 要检查 IP 伪装是否已启用(例如,对于 external 区),以 root 的身份输入以下命令:

    # firewall-cmd --zone=external --query-masquerade

    如果已启用,该命令会输出 yes,退出状态为 0。否则,会输出 no,退出状态为 1。如果省略 zone,将使用默认区。

  2. 要启用 IP 伪装,以 root 的身份输入以下命令:

    # firewall-cmd --zone=external --add-masquerade
  3. 要让此设置持久,请重复添加 --permanent 选项的命令。

要禁用 IP 伪装,以 root 身份输入以下命令:

# firewall-cmd --zone=external --remove-masquerade --permanent

46.8. 端口转发

使用此方法重定向端口只可用于基于 IPv4 的流量。对于 IPv6 重定向设置,您必须使用丰富的规则。

要重定向到外部系统,需要启用伪装。如需更多信息,请参阅配置 IP 地址伪装

46.8.1. 添加一个端口来重定向

使用 firewalld,您可以设置端口重定向,以便将所有进入的流量传送到您选择的其他内部端口或者另一台机器上的外部端口。

先决条件

  • 在您将从一个端口的流量重新指向另一个端口或另一个地址前,您必须了解 3 个信息:数据包到达哪个端口,使用什么协议,以及您要重定向它们的位置。

流程

  1. 将端口重新指向另一个端口:

    # firewall-cmd --add-forward-port=port=port-number:proto=tcp|udp|sctp|dccp:toport=port-number
  2. 将端口重定向到不同 IP 地址的另一个端口:

    1. 添加要转发的端口:

      # firewall-cmd --add-forward-port=port=port-number:proto=tcp|udp:toport=port-number:toaddr=IP
    2. 启用伪装:

      # firewall-cmd --add-masquerade

46.8.2. 将 TCP 端口 80 重定向到同一台机器中的 88 端口

按照以下步骤将 TCP 端口 80 重定向到端口 88。

流程

  1. 将端口 80 重定向到 TCP 流量的端口 88:

    # firewall-cmd --add-forward-port=port=80:proto=tcp:toport=88
  2. 使新设置具有持久性:

    # firewall-cmd --runtime-to-permanent
  3. 检查是否重定向了端口:

    # firewall-cmd --list-all

46.8.3. 删除重定向的端口

这个步骤描述了如何删除重定向的端口。

流程

  1. 要删除重定向的端口:

    # firewall-cmd --remove-forward-port=port=port-number:proto=<tcp|udp>:toport=port-number:toaddr=<IP>
  2. 要删除重定向到不同地址的转发端口:

    1. 删除转发的端口:

      # firewall-cmd --remove-forward-port=port=port-number:proto=<tcp|udp>:toport=port-number:toaddr=<IP>
    2. 禁用伪装:

      # firewall-cmd --remove-masquerade

46.8.4. 在同一台机器上将 TCP 端口 80 转发到端口 88

这个步骤描述了如何删除端口重定向。

流程

  1. 列出重定向的端口:

    ~]# firewall-cmd --list-forward-ports
    port=80:proto=tcp:toport=88:toaddr=
  2. 从防火墙中删除重定向的端口:

    ~]# firewall-cmd  --remove-forward-port=port=80:proto=tcp:toport=88:toaddr=
  3. 使新设置具有持久性:

    ~]# firewall-cmd --runtime-to-permanent

46.9. 管理 ICMP 请求

Internet Control Message ProtocolICMP)是一个支持协议,不同的网络设备使用它来发送错误信息和显示连接问题的操作信息,例如:请求的服务不可用。ICMP 与 TCP 和 UDP 等传输协议不同,因为它没有用来在系统间交换数据。

不幸的是,使用 ICMP 信息(特别是 echo-requestecho-reply )可能会公开您的网络信息,这些信息可能会被利用而造成安全隐患。因此, firewalld 启用阻止 ICMP 请求来保护您的网络信息。

46.9.1. 列出和阻塞 ICMP 请求

列出 ICMP 请求

ICMP 请求在位于 /usr/lib/firewalld/icmptypes/ 目录中的独立 XML 文件中描述。您可以阅读这些文件来查看请求的描述。firewall-cmd 命令控制 ICMP 请求操作。

  • 列出所有可用的 ICMP 类型:

    # firewall-cmd --get-icmptypes
  • IPv4、IPv6 或两个协议都可以使用 ICMP 请求。要查看 ICMP 请求使用的协议:

    # firewall-cmd --info-icmptype=<icmptype>
  • ICMP 请求的状态会显示为 yes (请求当前被阻塞)或 no (请求当前没有被阻塞)。检查 ICMP 请求当前是否被阻断:

    # firewall-cmd --query-icmp-block=<icmptype>

阻塞或取消阻塞 ICMP 请求

当您的服务器阻断 ICMP 请求时,它不会提供通常会提供的信息。但这并不意味着根本不给出任何信息。客户端收到特定 ICMP 请求被阻断的信息(拒绝)。应仔细考虑阻塞 ICMP 请求,因为它可能会造成通信问题,特别是 IPv6 流量。

  • 检查 ICMP 请求当前是否被阻断:

    # firewall-cmd --query-icmp-block=<icmptype>
  • 阻止 ICMP 请求:

    # firewall-cmd --add-icmp-block=<icmptype>
  • 删除 ICMP 请求的块:

    # firewall-cmd --remove-icmp-block=<icmptype>

在不提供任何信息的情况下阻断 ICMP 请求

通常,如果您阻断 ICMP 请求,客户端会知道您正在阻断它。这样潜在的攻击者仍然可以看到您的 IP 地址在线。要完全隐藏这些信息,您必须删除所有 ICMP 请求。

  • 阻塞和丢弃所有 ICMP 请求:
  • 将区的目标设置为 DROP:

    # firewall-cmd --permanent --set-target=DROP

现在,除您明确允许的流量外,所有流量(包括 ICMP 请求)将被丢弃。

阻塞或丢弃特定的 ICMP 请求,并允许其他请求:

  1. 将区的目标设置为 DROP:

    # firewall-cmd --permanent --set-target=DROP
  2. 添加 ICMP 块 inversion 以阻止所有 ICMP 请求:

    # firewall-cmd --add-icmp-block-inversion
  3. 为那些 ICMP 请求添加 ICMP 块:

    # firewall-cmd --add-icmp-block=<icmptype>
  4. 使新设置具有持久性:

    # firewall-cmd --runtime-to-permanent

block inversion 用来转换 ICMP 请求块的设置,因此所有之前没有阻断的请求都因为区的目标改变为 DROP 而被阻断。被阻断的请求不会被阻断。这意味着,如果您想要取消阻塞请求,则必须使用 blocking 命令。

将块 inversion 恢复到完全 permissive 设置:

  1. 将区的目标设置为 defaultACCEPT

    # firewall-cmd --permanent --set-target=default
  2. 删除 ICMP 请求的所有添加的块:

    # firewall-cmd --remove-icmp-block=<icmptype>
  3. 删除 ICMP 块 inversion:

    # firewall-cmd --remove-icmp-block-inversion
  4. 使新设置具有持久性:

    # firewall-cmd --runtime-to-permanent

46.9.2. 使用 GUI 配置 ICMP 过滤器

  • 要启用或禁用 ICMP 过滤器,启动 firewall-config 工具并选择过滤消息的网络区。选择 ICMP Filter 标签并选择您要过滤的每种 ICMP 消息类型的复选框。清除复选框以禁用过滤器。这个设置按方向设置,默认允许所有操作。
  • 要编辑 ICMP 类型,启动 firewall-config 工具并在标记为 Configuration 的菜单中选择 Permanent 模式。在 Services 窗口的底部会显示附加图标。选择 Yes 启用伪装并转发到另一台机器工作。
  • 要启用反向 ICMP Filter,请点击右侧的 Invert Filter 复选框。现在只接受标记为 ICMP 的类型,所有其他都被拒绝。在使用 DROP 目标的区域里它们会被丢弃。

46.10. 使用 firewalld

要查看 firewalld 支持的 IP 集合类型列表,以 root 用户身份输入以下命令。

~]# firewall-cmd --get-ipset-types
hash:ip hash:ip,mark hash:ip,port hash:ip,port,ip hash:ip,port,net hash:mac hash:net hash:net,iface hash:net,net hash:net,port hash:net,port,net

46.10.1. 使用 CLI 配置 IP 设置选项

IP 集可以在 firewalld 区域中用作源,也可以作为丰富的规则的源使用。在 Red Hat Enterprise Linux 中,首选的方法是使用在直接规则 firewalld 中创建的 IP 集合。

  • 要列出永久环境中 firewalld 已知的 IP 集,请使用以下命令 root

    # firewall-cmd --permanent --get-ipsets
  • 要添加新 IP 集,以 root 身份运行以下命令:

    # firewall-cmd --permanent --new-ipset=test --type=hash:net
    success

    以上命令为 IPv4 创建了名称为 test 类型为 hash:net 的新 IP 设置。要创建用于 IPv6 的 IP 集,添加 --option=family=inet6 选项。要使新设置在运行时环境中有效,请重新载入 firewalld

  • 使用以下命令列出新 IP 设置:root

    # firewall-cmd --permanent --get-ipsets
    test
  • 要获得有关 IP 集的更多信息,以 root 用户身份运行以下命令:

    # firewall-cmd --permanent --info-ipset=test
    test
    type: hash:net
    options:
    entries:

    请注意,IP 集目前没有任何条目。

  • 要在 test IP 集中添加一个项,以 root 身份运行以下命令:

    # firewall-cmd --permanent --ipset=test --add-entry=192.168.0.1
    success

    前面的命令将 IP 地址 192.168.0.1 添加到 IP 集合中。

  • 要获取 IP 集合中当前条目列表,以 root 用户身份运行以下命令:

    # firewall-cmd --permanent --ipset=test --get-entries
    192.168.0.1
  • 生成包含 IP 地址列表的文件,例如:

    # cat > iplist.txt <<EOL
    192.168.0.2
    192.168.0.3
    192.168.1.0/24
    192.168.2.254
    EOL

    包含 IP 集合 IP 地址列表的文件应该每行包含一个条目。以 hash、分号或空行开头的行将被忽略。

  • 要添加 iplist.txt 文件中的地址,以 root 身份运行以下命令:

    # firewall-cmd --permanent --ipset=test --add-entries-from-file=iplist.txt
    success
  • 要查看 IP 集合的扩展条目列表,以 root 身份运行以下命令:

    # firewall-cmd --permanent --ipset=test --get-entries
    192.168.0.1
    192.168.0.2
    192.168.0.3
    192.168.1.0/24
    192.168.2.254
  • 要从 IP 集合中删除地址并检查更新的条目列表,以 root 身份运行以下命令:

    # firewall-cmd --permanent --ipset=test --remove-entries-from-file=iplist.txt
    success
    # firewall-cmd --permanent --ipset=test --get-entries
    192.168.0.1
  • 您可以将 IP 集合作为一个源添加到区,以便处理所有来自 IP 集合中列出的任意地址的网络流量。例如:要将 test IP 集添加为 drop 区的一个源,以便丢弃所有来自在 test IP 集中列出的所有条目的所有数据包,以 root 身份运行以下命令:

    # firewall-cmd --permanent --zone=drop --add-source=ipset:test
    success

    源中的 ipset: 前缀显示 firewalld,源是一个 IP 集,而不是一个 IP 地址或地址范围。

只有创建和删除 IP 集限于永久环境,其它所有 IP 设置选项也可以在运行时环境中使用,即使没有 --permanent 选项。

警告

红帽不推荐使用不是通过 firewalld 管理的 IP 集。要使用这样的 IP 组,需要一个永久直接规则来引用集合,且必须添加自定义服务来创建这些 IP 组件。这个服务需要在 firewalld 启动前启动,否则 firewalld 无法使用这些组添加直接规则。您可以使用 /etc/firewalld/direct.xml 文件添加永久直接规则。

46.11. 丰富规则的优先级

默认情况下,丰富的规则会根据其规则操作进行组织。例如: deny 规则优先于 allow 规则。priority 参数丰富的规则可让管理员对丰富的规则及其执行顺序进行精细的控制。

46.11.1. priority 参数如何将规则组织为不同的链

您可以将 priority 参数设置为在 -3276832767 之间的任意数量,较低值具有更高的优先级。

firewalld 服务根据优先级值在不同的链中组织规则:

  • 优先级低于 0:规则被重定向到带有 _pre 后缀的链中。
  • 优先级高于 0:规则被重定向到使用 _post 后缀的链中。
  • 优先级等于 0:基于操作,规则会被重定向到带有 _log_deny_allow 操作的链中。

在这些子链中,firewalld 会根据其优先级值对规则排序。

46.11.2. 设置丰富的规则的优先级

以下流程介绍了一个示例,它创建了一个丰富的规则,它使用 priority 参数记录被他规则不允许或拒绝的所有流量。您可以使用此规则标记意非预期的流量。

流程

  1. 添加一个带有非常低优先级的丰富规则来记录未由其他规则匹配的所有流量:

    # firewall-cmd --add-rich-rule='rule priority=32767 log prefix="UNEXPECTED: " limit value="5/m"'

    这个命令还会将日志条目数限制为每分钟 5 个。

  2. 另外,显示上一步中命令创建的 nftables 规则:

    # nft list chain inet firewalld filter_IN_public_post
    table inet firewalld {
      chain filter_IN_public_post {
        log prefix "UNEXPECTED: " limit rate 5/minute
      }
    }

46.12. 配置防火墙锁定

如果本地应用程序或服务是作为 root 运行的,(例如: libvirt),则可以更改防火墙配置。使用这个特性,管理员可以锁定防火墙配置,从而达到没有应用程序或只有添加到锁定白名单中的应用程序可以请求防火墙更改的目的。锁定设置默认会被禁用。如果启用,用户就可以确定,防火墙没有被本地的应用程序或服务进行了不必要的配置更改。

46.12.1. 使用 CLI 配置锁定

这个步骤描述了如何使用命令行启用或禁用锁定。

  • 要查询是否启用锁定,使用以下命令: root

    # firewall-cmd --query-lockdown

    如果启用了锁定,则命令会输出 yes,退出状态为 0。否则,它会输出 no,退出状态为 1

  • 要启用锁定,以 root 身份输入以下命令:

    # firewall-cmd --lockdown-on
  • 要禁用锁定,以 root 身份运行以下命令:

    # firewall-cmd --lockdown-off

46.12.2. 使用 CLI 配置锁定允许列表选项

锁定允许名单中可以包含命令、安全上下文、用户和用户 ID。如果允许列表中的命令条目以星号"*"结尾,则所有以该命令开头的命令行都匹配。如果没有 "*",那么包括参数的绝对命令必须匹配。

  • 上下文是正在运行的应用程序或服务的安全(SELinux)上下文。要获得正在运行的应用程序的上下文,请使用以下命令:

    $ ps -e --context

    该命令返回所有正在运行的应用程序。通过 grep 工具管道输出以便获取您感兴趣的应用程序。例如:

    $ ps -e --context | grep example_program
  • 要列出允许列表中的所有命令行,以 root 身份输入以下命令:

    # firewall-cmd --list-lockdown-whitelist-commands
  • 要在允许列表中添加 命令 command,以 root 身份输入以下命令:

    # firewall-cmd --add-lockdown-whitelist-command='/usr/bin/python3 -Es /usr/bin/command'
  • 要从允许列表中删除 命令 command,以 root 身份输入以下命令:

    # firewall-cmd --remove-lockdown-whitelist-command='/usr/bin/python3 -Es /usr/bin/command'
  • 要查询 command 命令是否在 allowlist 中,以 root 身份输入以下命令:

    # firewall-cmd --query-lockdown-whitelist-command='/usr/bin/python3 -Es /usr/bin/command'

    如果为 true,该命令会输出 yes,退出状态为 0。否则,它会输出 no,退出状态为 1

  • 要列出允许列表中的所有安全上下文,以 root 身份输入以下命令:

    # firewall-cmd --list-lockdown-whitelist-contexts
  • 要在允许列表 添加上下文 context,以 root 身份输入以下命令:

    # firewall-cmd --add-lockdown-whitelist-context=context
  • 要从允许列表 删除上下文 context,以 root 身份输入以下命令:

    # firewall-cmd --remove-lockdown-whitelist-context=context
  • 要查询上下文 context 是否在允许列表中,以 root 身份输入以下命令:

    # firewall-cmd --query-lockdown-whitelist-context=context

    如果为 true,输出 yes,退出状态为 0,否则输出 1,退出状态为 no

  • 要列出允许列表中的所有用户 ID,以 root 身份输入以下命令:

    # firewall-cmd --list-lockdown-whitelist-uids
  • 要在允许列表中添加用户 ID uid,以 root 身份输入以下命令:

    # firewall-cmd --add-lockdown-whitelist-uid=uid
  • 要从允许列表中删除用户 ID uid,以 root 身份输入以下命令:

    # firewall-cmd --remove-lockdown-whitelist-uid=uid
  • 要查询用户 ID uid 是否在 allowlist 中,请输入以下命令:

    $ firewall-cmd --query-lockdown-whitelist-uid=uid

    如果为 true,输出 yes,退出状态为 0,否则输出 1,退出状态为 no

  • 要列出允许列表中的所有用户名,以 root 身份输入以下命令:

    # firewall-cmd --list-lockdown-whitelist-users
  • 要在允许列表中添加用户名 user,以 root 身份输入以下命令:

    # firewall-cmd --add-lockdown-whitelist-user=user
  • 要从允许列表中删除用户名 user,以 root 身份输入以下命令:

    # firewall-cmd --remove-lockdown-whitelist-user=user
  • 要查询用户名 user 是否在 allowlist 中,请输入以下命令:

    $ firewall-cmd --query-lockdown-whitelist-user=user

    如果为 true,输出 yes,退出状态为 0,否则输出 1,退出状态为 no

46.12.3. 使用配置文件配置锁定的 allowlist 选项

默认 allowlist 配置文件包含 NetworkManager 上下文和 libvirt 默认上下文。用户 ID 0 也位于列表中。

<?xml version="1.0" encoding="utf-8"?>
	<whitelist>
	  <selinux context="system_u:system_r:NetworkManager_t:s0"/>
	  <selinux context="system_u:system_r:virtd_t:s0-s0:c0.c1023"/>
	  <user id="0"/>
	</whitelist>

以下是一个允许名单配置文件示例,为 firewall-cmd 工具程序启用所有命令,对于一个名为 user,用户 ID 为 815 的用户:

<?xml version="1.0" encoding="utf-8"?>
	<whitelist>
	  <command name="/usr/libexec/platform-python -s /bin/firewall-cmd*"/>
	  <selinux context="system_u:system_r:NetworkManager_t:s0"/>
	  <user id="815"/>
	  <user name="user"/>
	</whitelist>

这个示例显示 user iduser name,但只需要一个选项。Python 是程序解释器,它位于命令行的前面。您还可以使用特定的命令,例如:

/usr/bin/python3 /bin/firewall-cmd --lockdown-on

在这个示例中,只允许 --lockdown-on 命令。

在 Red Hat Enterprise Linux 中,所有工具都放置在 /usr/bin/ 目录中, /bin/ 目录被符号链接到 /usr/bin/ 目录。换句话说,虽然作为 root 输入 firewall-cmd 的路径时,可能会解析为 /bin/firewall-cmd,但现在可以使用 /usr/bin/firewall-cmd。所有新脚本都应该使用新位置。但请注意,如果以 root 身份运行的脚本被写入来使用 /bin/firewall-cmd 路径,则必须在允许列表中添加该命令路径,除了通常用于非root 用户的 /usr/bin/firewall-cmd 路径外。

一个命令的 name 属性末尾的 * 意味着,所有以这个字符串开头的命令都匹配。如果没有 *,包括参数的绝对命令必须匹配。