Linux的Firewalld防火墙

使用防火墙可以对外部的数据包进行过滤和阻止,尽可能减少暴露在网络上的危险以保护系统安全。在RHEL7系的Linux系统中,已经将iptables防火墙管理工具使用firewalld代替。这篇文章的所有案例在RHEL8上成功执行,如果遇到了问题请尝试变通或者在底部评论区与我留言。

1. firewalld防火墙简介

firewalld提供了一个动态管理的防火墙,在对防火墙规则修改时不需要断开连接就可以激活规则,并且支持网络区域zones,用来分配一个网络及相关连接一种程度上的信任。它已经对IPv4IPv6进行支持。并且可以选择对规则临时或永久修改。

1.1. firewalldiptables的主要区别

  • iptables/etc/sysconfig/iptables-config文件中存储配置。firewalld/etc/firewalld/下存储XML配置文件。

  • 使用iptables时每一个规则的更改意味着要清除所有旧的规则,然后从/etc/sysconfig/iptables-config配置文件中读取所有新的规则并载入。然而使用firewalld可以临时的将新添加的规则载入使用,不会像iptables一样丢失连接。

使用iptables命令行和firewalld工具和内核的NetFilter(内核防火墙框架)的交互示意图如下。

可以看出NetFilter才是真正的“防火墙”,它是Linux操作系统核心层内部的一个数据包处理框架,由图可以看出,不论是iptables命令行工具还是firewalld工具,它们都会通过iptables commandNetFilter(内核防火墙框架)放出来的接口实现沟通并使防火墙的规则生效。

1.2. 对firewalldZone网络区的理解

基于对网络中的设备和通信所给予的信任程度不同,firewalld防火墙可以用来将网络分割成不同的区域。 使用firewall-cmd --get-zones查看默认提供的zone,这些zone提供了一些基本的规则,也可以修改并保存规则。比如在工作单位时我切换到homeZone来屏蔽大多数让我分心的网络连接,然而回家后我需要娱乐娱乐,此时我将Zone改为home或者我信任我家里的网络并且改为了trustZone,这样又可以悠闲的享受那些娱乐网站咯。

Zone类型

说明

block

封锁

任何的连接都会被拒绝接收,并返回icmp(6)-host-prohibited拒绝信息

dmz

非军事区

处于此区域的设备可以公开访问,可以有限制的进入内部网络,仅接收经过选择的连接

drop

抛弃

接收到的任何连接都会被悄无声息的抛弃掉,不返回任何相应,仅允许对外发出的连接

external

外部

不信任来自网络的所有连接,仅接收经过选择的连接

home

家庭区

用于家庭网络。信任网络中的大多数连接,仅接收经过选择的连接

internal

内部

与home提供的默认规则相同

public

公共

不能相信网络内的其他计算机不会对您的计算机造成危害,仅接收经过选择的连接

trust

信任

可以接受任何的网络连接

work

工作

与public提供的默认规则相同

上面的所有Zones每个网络接口可以使用一个Zone作为当前Zone。当接入网络连接后,NetWorkManager将被分配为你设定好的默认Zone网络区,firewalld默认的网络区为public

2. 安装firewalld防火墙

安装firewalld需要以root用户身份执行下面的命令,并且执行firewalld命令时也要使用root用户身份执行。 dnf install firewalld 如果你安装了系统图形界面,并且也想使用图形化工具来管理firewalld,请执行如下命令。 dnf install firewall-config 但是本文中不会涉及到使用图形化工具配置firewalld防火墙

2.1. 启动防火墙

设置firewalld防火墙为默认防火墙并随着系统启动服务 systemctl enable firewalld 启动防火墙 systemctl start firewalld

如果对systemctl命令不了解,可以在浏览守护进程和控制服务相关博文。

2.2. 检查防火墙是否运行

systemctl status firewalld.service

systemctl status firewalld.service
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2020-02-05 08:03:45 CST; 10h ago
     Docs: man:firewalld(1)
 Main PID: 1539 (firewalld)
    Tasks: 2 (limit: 49252)
   Memory: 35.7M
   CGroup: /system.slice/firewalld.service
           └─1539 /usr/libexec/platform-python -s /usr/sbin/firewalld --nofork --nopid

Feb 05 08:03:44 centos8 systemd[1]: Starting firewalld - dynamic firewall daemon...
Feb 05 08:03:45 centos8 systemd[1]: Started firewalld - dynamic firewall daemon.

使用firewall-cmd --state也可以查看防火墙运行状态

firewall-cmd --state
running # 运行中

3. 使用firewall-cmd进行管理

3.1. Zone网络区管理

3.1.1. 查看所有Zone网络区

firewall-cmd --list-all-zones 列出所有Zone的配置规则

firewall-cmd --list-all-zones 
block
  target: %%REJECT%%
  icmp-block-inversion: no
  interfaces: 
  sources: 
...

还可以精简的只输出Zone的名字 firewall-cmd --get-zones

3.1.2. 查看firewalld默认Zone

firewall-cmd --get-default-zone

firewall-cmd --get-default-zone 
public  # `firewalld`默认Zone为public

3.1.3. 查询某个网络接口上使用的Zone

firewall-cmd --get-zone-of-interface=XXXX

firewall-cmd --get-zone-of-interface=ens32  # 这里查看ens32网络接口当前的Zone
public  # 当前ens32接口上激活的是`public`Zone

3.1.4. 查看已激活的Zone的网络接口列表

firewall-cmd --get-active-zones

firewall-cmd --get-active-zones       
public  
  interfaces: ens32

# 可以看到,当前只有public网络区被激活。并且只有一个网络接口`ens32`使用这个Zone

3.1.5. 查询某一个Zone的详细规则信息

firewall-cmd --zone=public --list-all

firewall-cmd --zone=public --list-all 
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens32
  sources: 
  services: cockpit dhcpv6-client ssh
  ports: 8096/tcp
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

  # 可以看到public网络区的规则信息:绑定了`ens32`网络接口,放行了cockpit dhcpv6-client ssh 服务的默认端口规则,还放行了8096的tcp端口。

3.1.6. 修改当前默认的Zone网络区

比如设置默认网络区为public,更改会立即生效。此时此刻,所有接口上默认绑定的Zone网络区都会切换到新的这个publicZone网络区上。 firewall-cmd --set-default-zone=public

3.1.7. 修改网络接口上的Zone网络区

如果有许多网络接口,要更改当前ens32网络接口绑定的Zone网络区为home,可以执行如下命令。 firewall-cmd --zone=home --change-interface=ens32

3.1.8. 删除绑定在网络接口上的Zone网络区

如果你不想让某以网络接口绑定到任何的网络区上,你可以执行如下命令。但是这么做无异于裸奔在网络世界中! firewall-cmd --remove-interface=ens32

firewall-cmd --remove-interface=ens32 
You're performing an operation over default zone ('public') 
but your connections/interfaces are in zone 'trusted' (see --get-active-zones)
You most likely need to use --zone=trusted option.  # 由于没有加上--zone参数,这里给我们一个提示。

success

实际上任何一个网络接口都要绑定一个Zone网络区,如果将绑定的网络区删除,在reloadfirewall规则后会发现刚刚删除Zone的网络接口自动绑定到了trusted的Zone网络区,也就是说不受到防火墙的任何规则限制,比较危险。

3.2. 重新加载firewalld防火墙

3.2.1. 不中断用户连接

通常在对规则添加--permanent永久生效的选项后,规则不会立即生效,需要重新加载防火墙后配置的永久规则才会生效。在不中断用户现有的连接的情况下,建议使用firewall-cmd --reload来重新加载防火墙。 firewall-cmd --reload

3.2.2. 完全重载防火墙,并断开现有的用户连接

通常在firewalld防火墙出现问题时才会使用这种方式重载防火墙,这种方式会断开现有的网络连接,即丢失状态信息! firewall-cmd --complete-reload

3.3. 打开/关闭防火墙端口(放行端口)

如果本地需要开放一个端口供外部访问,那么你可以将这个端口添加到某一网络区的放行端口规则中。

3.3.1. 打开防火墙端口(放行端口)

firewall-cmd --add-port=portid[-portid]/protocol [--permanent] [--zone=zone] 参数(portid[-portid]):要开放的端口号,如果是一个范围则使用10000-12000表达一个范围。 参数(protocol):TCP/UDP协议 可选参数(zone):将规则添加到哪个Zone网络区中,如果缺省该参数则添加到默认Zone网络区中。 可选选项(–permanent):规则永久保存,重新加载防火墙后生效。如果缺省该参数则修改的规则立即生效,但是重新加载防火墙后规则会失效

firewall-cmd --add-port=6000-7000/tcp --permanent --zone=public # 在public网络区下放行6000~7000之间TCP通信协议的网络端口(闭区间),规则永久保存并且在下一次重新加载防火墙后生效。
success

firewall-cmd --zone=public --list-all # 检查修改后的public网络区的规则,发现并没有新添加的放行端口规则,说明规则还没有生效,需要重新加在防火墙。
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens32
  sources: 
  services: cockpit dhcpv6-client http https ssh
  ports: 8096/tcp
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 


firewall-cmd --reload # 重新加载防火墙

firewall-cmd --list-all --zone=public # 再次检查规则是否生效。发现规则已生效。
public
  target: default
  icmp-block-inversion: no
  interfaces: 
  sources: 
  services: cockpit dhcpv6-client http https ssh
  ports: 8096/tcp 6000-7000/tcp
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules: 

下面在默认的网络区内永久放行单个TCP端口

firewall-cmd --add-port=6000/tcp --permanent # 这里没有添加`--zone`的选项和参数,会自动添加到默认网络区中。

firewall-cmd --reload 重新加载防火墙,使规则生效。

3.3.2. 关闭防火墙端口(关闭端口)

刚刚已经将端口放行,并且暴露在外。如果需要这个端口的服务不再使用,出于安全考虑你可以将这个端口从放行规则中删除掉。 firewall-cmd --remove-port=portid[-portid]/protocol [--permanent] [--zone=zone] 参数(–remove-port=portid[-portid]/protocol):你要移除的端口号/端口范围,注意表明是TCP协议还是UDP协议哦。和你添加的时候一样,如果添加时你写的是一个端口范围,那么删除时只能将全部的端口范围删除掉,不能只删除端口范围中一部分端口。 可选参数(–zone=zone):关闭指定网络区中的端口,如果缺省该参数,则从默认的网络区中删除端口。 可选选项(–permanent):规则永久保存,重新加载防火墙后生效。如果缺省该参数则修改的规则立即生效,但是重新加载防火墙后规则会失效

firewall-cmd --remove-port=8080/tcp --permanent #关闭默认Zone网络区开放的TCP8080端口

firewall-cmd --remove-port=1000-2000/udp --zone=public --permanent  #永久关闭在public网络区下开放的UDP1000-2000端口。

3.4. 放行/关闭防火墙某一服务(放行服务)

firewalld中存储了常见服务的默认端口信息,如果你的服务没有更改过默认的端口号,那么可以直接使用firewald放行服务,它会根据默认规则,自动放行一个或一组此服务需要的端口。只需要管理员来记忆服务名就好咯!

3.4.1. 查看所有支持的服务

firewall-cmd --get-services 你能看到所有firewald存储的默认服务端口号,如果此时你需要开启某一服务的端口就不需要记他们默认的端口号了,试试firewall-cmd --add-service=XXXX

3.4.2. 查询服务端口详细信息

刚才查询到了所有支持的服务,那firewalld给我们提供的默认服务的端口号究竟是啥呢? firewall-cmd --permanent --service=https --get-port 返回443/tcp

3.4.3. 放行服务端口

firewall-cmd --add-service=service [--permanent] [--zone=zone] [--timeout=timeval] 参数(–add-service):要放行的服务名,如ssh、http、https。 可选参数(–zone=zone):将此规则添加到网络区,如果缺省该参数,添加到默认网络区内。 可选参数(–timeout=timeval):临时生效时间,不可与--permanent连用。表达方式可以是--timeout=[100s | 100m | 100h]。(timeval is either a number (of seconds) or number followed by one of characters s(seconds), m(minutes), h(hours)) 可选选项(–permanent):规则永久保存,重新加载防火墙后生效。如果缺省该参数则修改的规则立即生效,但是重新加载防火墙后规则会失效

firewall-cmd --add-service=https --permanent  #永久放行在默认网络区内的https(443端口)服务

firewall-cmd --add-service=https --timeout=1h #临时放行在默认网络区内的https服务1小时

firewwall-cmd --add-service=https --zone=home --permanent #永久放行在home网络区中的https服务

3.4.4. 关闭服务端口

如果关闭某一服务所对应的端口,那么将会时该服务无法对外部提供服务,请确定好删除的服务名,以免影响业务的正常服务! 你可以通过firewall-cmd --list-all查看默认网络区下,当前开放了哪些服务与规则,确保在关闭之前,这些服务和端口是开放的状态。 firewall-cmd --remove-service=https [--permanent] [--zone=zone] 参数与规则与关闭端口类似,在此不再赘述。

3.5. 端口转发

端口转发可以将到达某一端口的数据包转发到本机或其他机器上另一个的一个端口上。使用端口转发功能需要现开启firewalld的IP伪装功能。 使用firewall-cmd --list-forward-ports可以查询所有端口转发规则。

3.5.1. 开启IP伪装

防火墙可以实现IP伪装,默认为关闭状态。可以使用firewall-cmd --query-masquerade进行查询。 firewall-cmd --query-masquerade查询默认Zone网络区内的ip伪装功能是否开启。 返回no则为关闭状态。 firewall-cmd --add-masquerade [--permanent] [--zone=zone] [--timeout=timeval] 参数(–add-masquerade):开放IP转发功能。 可选参数(–zone=zone):将此规则添加到网络区,如果缺省该参数,添加到默认网络区内。 可选参数(–timeout=timeval):临时生效时间,不可与--permanent连用。表达方式可以是--timeout=[100s | 100m | 100h]。 可选选项(–permanent):规则永久保存,重新加载防火墙后生效。如果缺省该参数则修改的规则立即生效,但是重新加载防火墙后规则会失效。 如果不需要IP地址伪装,使用下面的命令关闭。 firewall-cmd --remove-masquerade [--permanent] [--zone=zone]

3.5.2. 开启端口转发

请确保在开启端口转发前已经开启IP伪装功能。 firewall-cmd --add-forward-port=port=portid[-portid]:proto=protocol[:toport=portid[-portid]][:toaddr=address[/mask]] [--permanent] [--zone=zone] [--timeout=timeval] 参数(–add-forward-port):

portid:本机端口号
protocal:UDP/TCP协议,此处只能选择一个。
[portid]:要转发到的端口。如果缺省该参数则默认与设置的本地端口一致。
[address]:要转发到的地址。如果缺省该参数则默认为本机地址。

可选选项(–permanent):规则永久保存,重新加载防火墙后生效。如果缺省该参数则修改的规则立即生效,但是重新加载防火墙后规则会失效。 其他参数不再赘述。 下面是一些使用端口转发的案例:

firewall-cmd --add-masquerade # 开启IP伪装(转发到其他IP上时必须开启,仅转发本地端口则非必须开启)


firewall-cmd --add-forward-port=port=8888:proto=udp:toport=53 --permanent #永久将本机默认网络区下的本地UDP8888端口转发到本地UDP53端口上。

firewall-cmd --add-forward-port=port=7777:proto=tcp:toport=6667:toaddr=192.168.1.160 --zone=public  #临时在public网络区下将本机7777端口的TCP流量转发到192.168.1.160上的6667端口上,重载防火墙后失效

firewall-cmd --add-forward-port=port=7777:proto=tcp:toport=6667:toaddr=192.168.1.160 --timeout=100s #临时在100秒内将默认网络区下将本机7777端口的TCP流量转发到192.168.1.160上的6667端口上,超时或重载防火墙后失效。

3.5.3. 关闭端口转发

使用 firewall-cmd --list-forward-ports查询当前已加载所有的端口转发规则

firewall-cmd --list-forward-ports #查询当前已加载所有的端口转发规则
port=8888:proto=udp:toport=53:toaddr= #发现有一个转发规则

当不需要这个规则时我们可以删除它。 firewall-cmd --remove-forward-port=port=portid[-portid]:proto=protocol[:toport=portid[-portid]][:toaddr=address[/mask]] [--permanent] [--zone=zone] [--timeout=timeval] 参数部分不再赘述。与添加时的意思相对应。可以先查询规则,确定好你要删除的规则后将规则填写到--remove-forward-port=后即可。

注意:如果你添加端口转发规则时,选择了--permanet永久生效,那么在永久删除时也要添加上--permanet选项。除非是想临时取消此这条规则。

firewall-cmd --list-forward-ports #查询当前已加载所有的端口转发规则
port=8888:proto=udp:toport=53:toaddr= #发现有一个转发规则,现在删除此规则。

firewall-cmd --remove-forward-port=port=8888:proto=udp:toport=53:toaddr=  --permanet  # 在默认的网络区内永久删除这条转发规则。

firewall-cmd --reload #使修改生效

待续