Linux防火墙详解
本文参考了《Linux就该这么学》、《鸟哥的Linux私房菜》、《RHCSA/RHCE红帽Linux认证学习指南》、《iptables零基础快速入门系列》、《Firewalld详解》、《Firewalld Rich Rules Explained with Examples》、《Firewalld – Understanding Rich Rules on CentOS/RHEL 7》
Linux中防火墙的实现主要是依托于Netfilter框架,通过该框架,其他内核模块才能够实现诸如包过滤、网络地址转换(NAT)以及负载均衡等功能。其中iptables就是最著名的命令行工具,主要实现了包过滤以及NAT。在RHEL7中,又提供了一种新的服务——firewalld,与iptables不同的是,firewalld不是基于“规则链”,而是基于区域。
1. iptables
1.1 iptables的基本概念
iptables会按照从上到下的顺序,依次检查规则链,因此应该将优先级较高的规则放在前面。
既然叫做iptables,说明其中是有一个基本的概念,叫做表(table)。所谓表就是具有相同功能的规则的集合,在iptables中默认有四种表:
- filter:用于对数据包进行过滤
- nat:用于进行网络地址转换
- mangle:拆解报文、做出修改、重新封装
- raw:关闭NAT表上启用的连接追踪功能
前面,我们又提到了iptables是一种基于“规则链”的应用,因此还需要明确,在iptables中存在链的概念,所谓链可以简单理解为计算机系统中的关卡,由于每个关卡下面有一串的规则(需要从上至下以此执行),因此每个关卡可以看作一条链状结构。其中默认有五种链,分别是:
- PREROUTING
- INPUT
- OUTPUT
- FORWARD
- POSTROUTING
具体的内容可以参考朱双印的技术博客,里面介绍的非常清楚了。以上就是我们经常听到的iptables中“四表五链”。
iptables中的动作主要包括以下几类:
- ACCEPT:允许数据包通过
- DROP:丢弃掉数据包,且不做任何响应
- REJECT:拒绝数据包,且在必要时给出响应
- LOG:记录日志信息到/var/log/message中
- REDIRECT:本机做端口映射
- SNAT:源地址转换
- DNAT:目的地址转换
1.2 iptables的基本操作
前面我们提到了表的概念,容易让人想到的就是关系型数据库中的表,对于这些表而言,最常见的操作就是“增删改查”(有点像相声里的说学逗唱哈)。让我们首先来看看iptables的查。
1.2.1 查
要想查看iptables中的规则内容,主要使用-L
参数。在前面我们也提到了所谓的“四表五链”,如果想要查看这些具体的“表”和“链”的内容,就需要添加额外的参数。
查看表
如果要想查看(或者说的更准确些是操作)指定的表,可以使用-t <tabletype>
参数,如果没有指定改参数,那么默认操作的是filter表。
查看链
要想查看链的内容,需要在-L
参数后面添加具体的链名(比如INPUT、PREROUTING等)
其他查看的参数
- --line-numbers:可以显示出规则的序号
- -v:可以显示出更为详细的信息
- -n:不对规则中的IP和端口等进行反解析(即显示IP地址和具体的端口号,没有该参数时会显示DNS的解析信息和服务名称)
1.2.2 增
在iptable中增加规则,主要有三个参数,分别是:
- -I
- -A
- -P
默认规则
-P
参数主要用于设置默认参数,其语法为:
iptables -t <表名> -P <链名> <动作>
其中表名部分可以省略,默认为filter表。下面我们来简单的看一个实例:
iptables -P INPUT ACCEPT
在这个例子中,没有指定-t参数,说明操作的是filter表。-P参数后面跟了INPUT链,说明该命令就是将filter表中的INPUT链的默认动作设置为ACCEPT,即在没有其他规则的情况下,将接受一切数据包
规则链尾部添加
-A
参数的全拼是append,即在规则链的尾部进行追加(即优先级最低的规则),其标准语法为:
iptables -t <表名> -A <链名> <匹配条件> -j <动作>
其中<表名>、<链名>和<动作>我们已经做了很多次说明了,此处就不再赘述了,我们重点来看一下匹配条件。所谓匹配条件是指当这个条件满足以后,我们就会执行-j后面的动作。那么匹配条件有哪些呢?常见的主要有以下几个:
- -s <地址>:源地址,可以用IP/MASK来表示,如果
-S
前面加了!
,则表示不匹配这个IP的时候满足条件,多个ip地址时,使用,
进行分割 - -d <地址>:目的地址(与
-s
参数相同) - -p <协议名称>:协议名称,比如tcp、udp、icmp等,不指定该参数时,默认为
all
- -i <网卡名称>:从这块网卡流入的数据
- -o <网卡名称>:从这块网卡流出的数据
- --dport <端口号>:匹配目标端口号,可以写为1000:1024,表示禁用1000-1024之间的所有端口
- --sport <端口号>:匹配源端口号
需要说明的是,当使用
--dport
和--sport
时,可以使用-m
参数来指定该规则针对的是哪个协议,例如:iptables -A INPUT -p tcp -s 192.168.10.0/24 -m tcp --sport 22 -j DROP
如果没有指定该参数,则会跟随
-p
参数指定的协议
规则链首部/指定位置添加
要想在规则链首部添加,就需要使用-I
参数,其标准语法为:
iptables -t <表名> -I <链名> <规则序号> <匹配条件> -j <动作>
除了优先级的差别外,-I
参数与-A
参数基本一致,唯一的差别在于-I
参数可以在<链名>后面添加<规则序号>
,即-I
不仅可以在链的首部添加规则,还可以在指定位置添加规则。
1.2.3 删
在iptables中,要想删除规则,有两个参数可供选择:
- -F
- -D
清空iptables
可以使用-F
参数来清空iptables规则库,其命令语法为:
iptables -t <表名> -F <链名>
如果不置顶链名则删除该表下的所有规则
删除满足特定条件的规则
要想删掉某一条规则,则需要使用-D
参数,使用时有两种语法,比较简单的是直接指定规则序号,即:
iptables -t <表名> -D <链名> <规则序号>
如果要想实现更灵活的删除,则可以使用带有匹配条件的语法:
iptables -t <表名> -D <链名> <匹配条件> -j <动作>
这种方法的灵活性比较强,可以一次删掉多条规则,但是其杀伤力比较大,建议操作之前一定要慎重
1.2.4 改
要想对规则进行修改,需要使用-R
参数,其具体语法命令为:
iptables -t <表名> -R <链名> <规则序号> <规则原本的匹配条件> -j <动作>
所谓<规则原本的匹配条件>是指不需要进行修改的规则,例如iptables详解(3)中给出了一个例子:
iptables -t filter -R INPUT 3 -s 192.168.1.146 -j ACCEPT
该命令表示修改filter表中INPUT链中的第3条规则,将这条规则的动作改为放行(ACCEPT),-s 192.168.1.146
表示这条规则中原本的匹配条件,如果此处不写这个条件的话,那么修改后的规则的源地址就有可能变为0.0.0.0/0(即anywhere)。所以在执行改命令时一定要慎之又慎!!!
1.3 保存
最后需要说明的是,执行上述命令后制定的各项规则,会在Linux重启后消失,所以要想让这些命令永久生效,就自然需要保存,即使用如下命令:
services iptables save
iptables会将最终的规则保存到
/etc/sysconfig/iptables
文件中
2 Firewall
在RedHat7.3中以后就不再支持iptables了,我个人猜测这可能是为了更好的推广新的防火墙firewall。firewall对应的服务名称是firewalld,其中又支持两个工具,其中一个是命令行的,一个是GUI的窗口:
- firewall-cmd
- firewall-config
在firewall中,引入了一个区域(zone)的概念,我们可以将区域理解为不同的套餐,以适应不同的场景。firewall中内置的区域主要包括:
区域 | 默认策略规则 |
---|---|
trusted | 允许所有的数据包 |
home | 适用于家庭场景,拒绝流入的流量(除非与流出流量有关);允许ssh、mdns、ipp-client、samba-client、dhcpv6-client服务的流量 |
internal | 适用于内部网络,与home区域一样 |
work | 适用于工作区域,拒绝流入的流量(除非与流出流量有关);允许ssh、ipp-client、dhcpv6-client服务的流量 |
public | 适用于公共区域,允许ssh和dhcpv6-client服务的流量,是firewall默认区域 |
external | 拒绝流入的流量(除非与流出流量有关),仅允许ssh服务的流量 |
dmz | 拒绝流入的流量(除非与流出流量有关),仅允许ssh服务的流量 |
block | 拒绝流入的流量(除非与流出流量有关) |
drop | 拒绝流入的流量(除非与流出流量有关),没有任何回复 |
在firewall中有两种运行模式,分别是:
- runtime:当前生效,重启无效
- permanent:当前无效,重启生效
要想配置permanent模式,需要使用--permanent
参数,使用之后还必须手动执行下面的命令:
firewall-cmd --reload
才能确保配置的策略立即生效!!!
2.1 区域管理
对于区域的管理,firewall可以使用的参数包括:
- --get-default-zone:查看默认的区域
- --set-default-zone:设置默认的区域
- --get-activate-zones:显示当前正在使用的区域与网卡名称
- --get-zones:查看可用的区域
- --list-all:查看当前区域的信息(包括:网卡配置参数、资源、端口、服务等信息)
- --list-all-zones:查看所有区域的信息
所谓“默认区域”是指当不指定操作的区域时(即不使用--zone
参数时),所有操作所作用的区域;而“激活区域”(即activate zones)则是指正在使用的区域,例如我们的电脑上只有一块网卡,那么如果我们把该网卡挂在public
区域,则激活区即为public
,如果服务器上有两块网卡,一块挂在public
,一块挂在dmz
,那么激活区就有两个,分别为public
和dmz
。
2.2 规则管理
对于规则的管理,和iptables非常类似,也涉及到规则的“增删查”。在firewall中,如果将一个服务/端口/协议添加(使用带有add的参数)到规则中,则会放行该服务/端口/协议,如果移除(使用带有remove的参数)一个服务/端口/协议,则会拒绝改改服务/端口/协议。
2.2.1 服务管理
在服务管理中,主要使用到以下几个参数
- --add-service=<服务名>:添加一个服务到放行列表中
- --remove-service=<服务名>:从放行列表中删除一个服务
- --query-service=<服务名>:查询服务是否在放行列表中
- --list-services:列出所有放行的服务
2.2.2 端口管理
在端口管理中,主要使用到以下几个参数:
- --add-port=<端口号>/<协议>:添加一个端口到放行列表中
- --remove-port=<端口号>/<协议>:从放行列表中移除一个端口
- --query-port=<端口号>/<协议>:查询某个端口是否放行
- --list-ports:列出所有的放行端口
如果已经放行/禁用了某个服务,而该服务使用的是默认端口号(比如http使用80端口),则使用--list-ports
和--query-port
是无法查询到的。
所有的服务和端口/协议的对应关系,都存储在/etc/lib/firewalld/services
下的xml文件中
2.2.3 源地址管理
在firewall中,将源地址作为source,其常用的参数主要有:
- --add-source=<源地址>:将此地址/网段的流量引入某个zone
- --remove-source=<源地址>:拒绝此地址/网段的流量进入某个zone
- --query-source=<源地址>:查询该地址/网段是否列入了放行列表
- --list-sources:列出所有放行的地址
需要注意的是,如果--add-source
添加了一个网段,比如192.168.20.0/24
那么,当使用--query-source=192.168.20.1
来查询具体的某个地址是否加入放行列表时,得到的结论仍然是no
2.2.4 网卡管理
常用的参数主要有如下几个:
- --add-interface=<网卡名称>:将网卡绑定到某个zone
- --remove-interface=<网卡名称>:将网卡与该zone进行解绑
- --query-interface=<网卡名称>:查询某网卡是否绑定到某个zone
- --list-interfaces:查看所有绑定到某个zone的网卡
2.2.5 一键断网/恢复
要想一键断网/恢复,需要使用下面两个参数:
- --panic-on:一键断网
- --panic-off:一键恢复
2.2.6 流量转发
要想进行流量转发,首先要打开masquerade
功能,我查了一下这个词,原意是“伪装、冒充”的意思,如果仔细看了前面的内容,不难猜出要打开这个功能,必然要使用带有add
的参数,因此可知打开masquerade的命令为(关闭自然是使用--remove-masquerade
)
firewall-cmd --permanent --add-masquerade
此处,我们没有指定域,因此操作的是默认域public
,而且我们又使用了--permanent
参数,因此如果要立即生效,必然是需要--reload
的。
打开masquerade
后,就可以进行流量的端口转发了,其命令格式为:
firewall-cmd --permanent -zone=<区域> --add-forward-port=port=<源端口号>:proto=<协议>:toport=<目的端口号>:toaddr=<目的ip地址>
例如,如果我们要将本地端口888端口的TCP协议的数据转发到22端口,即可以使用如下命令:
firewall-cmd --add-forward-port=port=888:proto=tcp:toport=22
2.2.7 富规则(Rich Rules)
如果想查看更详细的富规则的内容,可以使用如下命令(无法用tab补全):
man firewalld.richlanguage
我把富规则理解为一种更加简单的但是却可以制定更加灵活防火墙规则的脚本语言。在firewall中,仍然是使用add、remove、query、list来实现富规则的“增删改查”,其具体的含义就不做过多的说明了,前面的例子看多了,这里基本就水到渠成了。
- --add-rich-rule='<富规则>'
- --remove-rich-rule='<富规则>'
- --query-rich-rule='<富规则>'
- --list-rich-rule='<富规则>'
富规则的语法为:
rule
[source]
[destination]
service|port|protocol|icmp-block|masquerade|forward-port
[log]
[audit]
[accept|reject|drop]
其中:
- [source]:表示本条规则所关注的源IP地址/网段,可以写为
source address="192.168.20.0/24"
- [destination]:本条规则所关注的目的IP地址/网段,可以写为
destination address="192.168.20.0/24"
- service:是指firewall中提供的服务名称,其命令格式为
service name=<服务名称>
- port:端口号,命令格式为
port port=<端口/端口范围>
- protocal:协议名称,命令格式为
protocal value=<协议名称>
- Imp-block:用于阻断一个或多个ICMP类型。可以用
firewall-cmd --get-icmptypes
来获得支持的ICMP类型,icmp-block在内部使用 reject 动作,因此不允许指定动作。命令格式为icmp-block name=<icmptype_name>
- masquerade:
- forward-port:进行流量转发,命令格式为:
forward-port port=<源端口/端口范围> protocol=<协议名称> to-port=<目的端口> to-addr=<目的地址>
- log:
- audit:
网友评论