在介绍 iptables 之前,我们首先需要了解一下防火墙分类。
从逻辑上分类:
分 类 | 说 明 |
---|---|
主机防火墙 | 针对单个主机进行防护 |
网络防火墙 | 处于网络入口或边缘,针对网络入口进行防护,服务于防火墙背后的本地局域网 |
从物理上分类:
分 类 | 说 明 |
---|---|
硬件防火墙 | 通过硬件和软件的组合实现,性能高,成本高 |
软件防火墙 | 应用软件处理逻辑运行于通用硬件平台之上的防火墙,性能低,成本低 |
接下来就可以介绍iptables啦!其实iptables并不是真正意义上的防火墙,可以理解为一个管理工具,用户通过 iptables 将安全设定执行到对应的"安全框架"中,这个"安全框架"才是真正的防火墙,这个框架叫做netfilter。
netfilter/iptables (简称为iptables) 组成 Linux 平台下的包过滤防火墙,可用于添加、编辑和除去规则,完成封包过滤、封包重定向和网络地址转换(NAT)等功能。这些规则是在做信息包过滤决定时,防火墙所遵循和组成的规则。这些规则存储在专用的信息包过滤表 (table) 中, 而这些表集成在 Linux 内核中。在信息包过滤表中, 规则被分组放在链(chain) 中。
从上面我们了解到,防火墙是遵循管理员预先设定的规则行动。而规则一般的定义为:“我要对哪些包,在什么时候,进行哪些操作”。其中:
上述的那些规则,一般都是多条,将多条规则串到一个链条上的时候,就形成了 “链”。在 iptables 中包含5条链,每条链对应着不同的时候:
链 | 说 明 |
---|---|
PREROUTING | 数据包进入路由表之前 |
INPUT | 通过路由表后目的地为本机 |
FORWARDING | 通过路由表后, 目的地不为本机 |
OUTPUT | 由本机产生, 向外转发 |
POSTROUTIONG | 发送到网卡接口之前 |
那么报文的流向是怎么样的呢?报文目的主机不同,流向也是不同的:
报 文 | 流 向 |
---|---|
到本机某进程的报文 | PREROUTING → INPUT |
由本机转发的报文 | PREROUTING → FORWARDING → POSTROUTIONG |
由本机某进程发出的报文 | OUTPUT → POSTROUTIONG |
前面了解到,链上有多条规则,那么这些规则是不是可以合并呢?当然是可以的!我们把功能相同的一些规则合并,这些具有相同功能的规则的集合就叫做 “表(table)”。在 iptables 中包含4种表,每种表对应着不同的功能:
表 | 说 明 |
---|---|
filter 表 | 一般的过滤功能 |
nat 表 | 网络地址转换功能 |
mangle 表 | 拆解报文,作出修改,并重新封装的功能 |
raw 表 | 关闭nat表上启用的连接追踪机制 |
在认识表和链之后,再来了解一下它们之间的关系。之前说,表是链上的一些具有相同功能规则的集合,那么是不是所有的表都存在于每一条链上呢?答案是否定的!
链 | 表 |
---|---|
PREROUTING | raw表、mangle表、nat表 |
INPUT | mangle表、filter表(CentOS7中还有nat表) |
FORWARD | mangle表、filter表 |
OUTPUT | raw表、mangle表、nat表、filter表 |
POSTROUTING | mangle表、nat表 |
在实际的使用过程中,我们通常是通过"表"作为入口,对规则进行操作的,所以这里需要列出"表"与"链"的关系:
表 | 链 |
---|---|
raw表 | PREROUTING、OUTPUT |
mangle表 | PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING |
nat表 | PREROUTING、FORWARD、POSTROUTING(CentOS7中还有INPUT) |
filter表 | INPUT、FORWARD、OUTPUT |
需要注意的一点,当数据包经过一条"链"时,会将当前链的所有规则都匹配一遍,但匹配的时候要遵循一定的顺序。那么哪个"表"中的规则会放在"链"的最前面优先匹配呢?这就存在一个优先级的问题!
当4张表同处于一条"链"时,执行优先级是这样的(由高而低):raw → mangle → nat → filter
现在我们都知道,匹配条件和处理动作共同组成了规则。如果满足匹配条件,就执行对应的动作;如果不满足,就判断下一条规则。那么该如何对规则进行管理呢?基本语法格式:iptables [ -t 表名 ] [ 命令选项 ] [ 链名 ] [ 匹配条件 ] [ -j 处理动作 ]
选 项 | 说 明 |
---|---|
-A | 在指定链尾部添加规则 |
-I | 在指定链指定位置添加规则,默认在首部添加 |
-R | 修改、替换指定链的某一条规则 |
-D | 删除指定链的某一条规则 |
-F | 清空指定链或所有链的规则 |
-L/S | 列出指定链或所有链的规则 |
-N | 创建用户自定义链 |
-X | 删除指定的用户自定义链 |
-P | 为指定链设置默认规则策略,对自定义链无效 |
-E | 更改自定义链的名称 |
-Z | 将指定链或所有连的计数器清零 |
-n | 解析IP地址,IP地址和端口号以数字形式显示 |
-v | 列出详细信息 |
–line-numbers | 显示规则序号 |
匹配条件分为基础匹配条件和扩展匹配条件。其中,基本匹配条件可以直接使用,而再使用扩展匹配条件前需要指定依赖扩展的模块才行。这里我们先了解基本匹配条件。
匹配条件 | 说 明 |
---|---|
-p tcp/udp/icmp/all | 匹配协议 |
-s addr1[,addr2] | 匹配源地址(可指定多个离散的IP地址) |
-d add1[,addr2] | 匹配目的地址(可指定多个离散的IP地址) |
–sport port1[:port2] | 匹配源端口(可指定一个连续的端口范围) |
–dport port1[:port2] | 匹配目的端口(可指定一个连续的端口范围) |
-o interface | 匹配出口网卡(只适用FORWARD、POSTROUTING和OUTPUT) |
-i interface | 匹配入口网卡(只适用FORWARD、POSTROUTING和INPUT) |
条 件 | 说 明 |
---|---|
ACCEPT | 允许数据包通过 |
DROP | 直接丢弃数据包,不给任何回应信息,这时数据发送端只有请求超时时才会有反应 |
REJECT | 拒绝数据包通过,这时会给数据发送端发送一个拒绝响应信息 |
SNAT | 源地址转换 |
MASQUERADS | SNAT的一种的形式,适用于动态的、临时会变的 ip 上 |
DNAT | 目标地址转换 |
REDIRECT | 在本机做端口映射 |
LOG | 在 /var/log/messages 文件记录日志信息,然后将数据包传递给下一条规则 |
两台服务器进行演示:
服务器A:localhost 192.168.140.137
服务器B:localhost123 192.168.140.128
① 首先清空服务器A防火墙规则;
[root@localhost ~]# iptables -F //清空规则
[root@localhost ~]# iptables -nvL //查看已经没有任何规则
Chain INPUT (policy ACCEPT 19 packets, 1381 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 9 packets, 872 bytes)
pkts bytes target prot opt in out source destination
#清空规则后,可以看到INPUT、FORWORD、OUTPUT默认策略都是ACCEPT,也就是说默认当前所有发往本机的报文都将放行。
------------------------
[root@localhost123 ~]# ping 192.168.140.137 //当前服务器A上没有任何规则,可以ping通
PING 192.168.140.137 (192.168.140.137) 56(84) bytes of data.
64 bytes from 192.168.140.137: icmp_seq=1 ttl=64 time=1.05 ms
64 bytes from 192.168.140.137: icmp_seq=2 ttl=64 time=0.255 ms
64 bytes from 192.168.140.137: icmp_seq=3 ttl=64 time=0.315 ms
② 增加规则;
[root@localhost ~]# iptables -t filter -I INPUT -s 192.168.140.128 -j REJECT //新增规则:拒绝来自192.168.140.128的所有报文
[root@localhost ~]# iptables -nvL
Chain INPUT (policy ACCEPT 24 packets, 1536 bytes)
pkts bytes target prot opt in out source destination
0 0 REJECT all -- * * 192.168.140.128 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 13 packets, 1144 bytes)
pkts bytes target prot opt in out source destination
#下面对-v选项的各字段含义进行解释:
#pkts:对应规则匹配到的报文的个数
#bytes:对应匹配到的报文包的大小总和
#target:规则对应的target,往往表示规则对应的"动作",即规则匹配成功后需要采取的措施
#prot:表示规则对应的协议,是否只针对某些协议应用此规则
#opt:表示规则对应的选项
#in:表示数据包由哪个接口(网卡)流入,我们可以设置通过哪块网卡流入的报文需要匹配当前规则
#out:表示数据包由哪个接口(网卡)流出,我们可以设置通过哪块网卡流出的报文需要匹配当前规则
#source:表示规则对应的源头地址,可以是一个IP,也可以是一个网段
#destination:表示规则对应的目标地址。可以是一个IP,也可以是一个网段
------------------------
[root@localhost123 ~]# ping 192.168.140.137 //无法ping通
PING 192.168.140.137 (192.168.140.137) 56(84) bytes of data.
From 192.168.140.137 icmp_seq=1 Destination Port Unreachable
From 192.168.140.137 icmp_seq=2 Destination Port Unreachable
From 192.168.140.137 icmp_seq=3 Destination Port Unreachable
------------------------
[root@localhost ~]# iptables -nvL //再次查看,pkts和bytes中已有包
Chain INPUT (policy ACCEPT 31 packets, 2578 bytes)
pkts bytes target prot opt in out source destination
5 420 REJECT all -- * * 192.168.140.128 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 21 packets, 2272 bytes)
pkts bytes target prot opt in out source destination
[root@localhost ~]# iptables -t filter -I INPUT -s 192.168.140.128 -j ACCEPT //新增规则:允许来自192.168.140.128的所有报文通过
[root@localhost ~]# iptables -nvL
Chain INPUT (policy ACCEPT 6 packets, 384 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- * * 192.168.140.128 0.0.0.0/0
5 420 REJECT all -- * * 192.168.140.128 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 3 packets, 328 bytes)
pkts bytes target prot opt in out source destination
------------------------
[root@localhost123 ~]# ping 192.168.140.137 //可以ping通
PING 192.168.140.137 (192.168.140.137) 56(84) bytes of data.
64 bytes from 192.168.140.137: icmp_seq=1 ttl=64 time=0.302 ms
64 bytes from 192.168.140.137: icmp_seq=2 ttl=64 time=0.267 ms
64 bytes from 192.168.140.137: icmp_seq=3 ttl=64 time=0.246 ms
#在这里就存在一个规则顺序问题:如果报文被前面的规则匹配到并执行对应动作,即使后面的规则也能匹配到当前报文,但已经没有机会再对报文执行相应的动作了。
③ 删除规则;
#方式一:
[root@localhost ~]# iptables -t filter -D INPUT 1
[root@localhost ~]# iptables -nvL
Chain INPUT (policy ACCEPT 26 packets, 1760 bytes)
pkts bytes target prot opt in out source destination
5 420 REJECT all -- * * 192.168.140.128 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 16 packets, 1440 bytes)
pkts bytes target prot opt in out source destination
#方式二:
[root@localhost ~]# iptables -D INPUT -s 192.168.140.128 -j REJECT
[root@localhost ~]# iptables -nvL
Chain INPUT (policy ACCEPT 6 packets, 384 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 3 packets, 312 bytes)
pkts bytes target prot opt in out source destination
④ 修改规则;
[root@localhost ~]# iptables -t filter -I INPUT -s 192.168.140.128 -j ACCEPT //新增规则:允许来自192.168.140.128的所有报文通过
[root@localhost ~]# iptables -nvL
Chain INPUT (policy ACCEPT 32 packets, 2048 bytes)
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- * * 192.168.140.128 0.0.0.0/0
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 16 packets, 1472 bytes)
pkts bytes target prot opt in out source destination
[root@localhost ~]# iptables -t filter -R INPUT 1 -s 192.168.140.128 -j DROP //修改规则:丢弃来自192.168.140.128的所有报文
[root@localhost ~]# iptables -nvL
Chain INPUT (policy ACCEPT 6 packets, 384 bytes)
pkts bytes target prot opt in out source destination
0 0 DROP all -- * * 192.168.140.128 0.0.0.0/0
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 4 packets, 368 bytes)
pkts bytes target prot opt in out source destination
#除了修改链已存在的规则之外,还能修改链的默认规则
[root@localhost ~]# iptables -t filter -P INPUT DROP
[root@localhost ~]# iptables -nvL //可以看到INPUT链的默认规则已改变为DROP
Chain INPUT (policy `DROP` 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
61 3928 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 26 packets, 2320 bytes)
pkts bytes target prot opt in out source destination
⑤ 保存规则;
#之前的操作中所有的规则的配置都是临时的,当重启服务或服务器后,规则就会消失,如果想永久保存,就要执行一些命令
#CentOS6与CentOS7中的情况稍微有些不同
#CentOS6中使用service iptables save命令即可保存规则,规则默认保存在/etc/sysconfig/iptables文件中
[root@localhost ~]# service iptables save
iptables: Saving firewall rules to /etc/sysconfig/iptables:[ OK ]
[root@localhost ~]# cat /etc/sysconfig/iptables
# Generated by iptables-save v1.4.7 on Mon May 25 20:22:04 2020
*filter
:INPUT ACCEPT [77:5333]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [46:4368]
-A INPUT -s 192.168.140.128/32 -j DROP
COMMIT
# Completed on Mon May 25 20:22:04 2020
#CentOS7中已经不能使用类似service iptables start这样的命令,并且使用firewall代替iptables service
#可以通过yum源安装iptables和iptables-services(其中iptables一般会被默认安装,但iptables-services一般不会被默认安装)
#安装完成后即可像CentOS6中一样通过service iptables save命令保存规则
#CentOS7中配置iptables-services步骤:
[root@localhost etc]# yum install iptables-services -y //配置好yum源后安装iptables-service
[root@localhost ~]# systemctl stop firewalld //停止firewalld
[root@localhost ~]# systemctl disable firewalld //禁止Firewalld自动启动
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
[root@localhost ~]# systemctl start iptables //启动iptables
[root@localhost ~]# systemctl enable iptables //将iptables设置为开机自动启动,以后即可通过iptables-service控制iptables服务
Created symlink from /etc/systemd/system/basic.target.wants/iptables.service to /usr/lib/systemd/system/iptables.service.
#还可以通过另一种通用方法保存规则,那就是使用iptables-save命令
#但iptables-save并不保存当前的规则,但是可以将当前的规则以"保存后的格式(也就是上面的文件内容格式)"输出到屏幕上
#利用这一点,相信大家已经想到了,配合重定向到/etc/sysconfig/iptables文件中即可
[root@localhost ~]# iptables-save > /etc/sysconfig/iptables
#我们也可以将/etc/sysconfig/iptables中的规则重新载入为当前iptables规则。
#但需要注意的是,未保存到/etc/sysconfig/iptables文件中的规则会被覆盖或丢失
[root@localhost ~]# iptables-restore < /etc/sysconfig/iptables
扩展匹配条件又可分为显式扩展和隐式扩展。其中,显式扩展是必须使用 -m 选项指明要调用的扩展模块;隐式扩展是在使用 -p 选项指明了特定的协议时,如果这个扩展匹配条件所依赖的扩展模块名正好与 -p 对应的协议名称相同,那么则可省略 -m 选项。这么说可能大家不太明白,那么我们继续向下看。
① tcp扩展模块
tcp扩展模块可以用来指定单个或者一个连续的端口范围,当需要指定一个连续的端口范围时,使用 起始端口号:末尾端口号 这样的格式。需要注意的是,在指定端口号之前,必须先指定使用的协议(即使用-p选项)。
匹配条件 | 说 明 |
---|---|
--sport port1[:prot2] | 匹配源端口 |
--dport port1[:prot2] | 匹配目的端口 |
举一个栗子,可以直观看到隐式扩展的省略形式。拒绝shh工具远程连接主机;
#sshd服务默认使用22端口,tcp协议
[root@localhost ~]# iptables -t filter -I INPUT -p tcp -m tcp --dport 22 -j REJECT
#-p指定的tcp协议与-m使用的tcp模块名称相同,所以可以省略-m选项
[root@localhost ~]# iptables -t filter -I INPUT -p tcp --dport 22 -j REJECT
如果想指定一段连续的端口范围,如果想匹配目的端口为22、23和24三个端口,可以使用:--dport 22:24
。
同时扩展匹配条件可以取反,比如:! --dport 22
表示目标端口不是22的报文将会被匹配到。
② multiport扩展模块
multiport扩展模块用来指定多个离散的、不连续的端口,每个端口之间用逗号隔开。
匹配条件 | 说 明 |
---|---|
--sport port1[,prot2] | 匹配源端口 |
--dport port1[,prot2] | 匹配目的端口 |
同样是上面的栗子,如果想匹配目的端口为22、23和24三个端口,当然范围比较小,可以使用multiport模块来指定多个离散的端口,就像这样:-m multiport -dport 22,23,24
。
③ iprange扩展模块
在使用-s和-d选项指定源地址和目标地址时只能指定一个或多个离散的、不连续的IP地址。而iprange扩展模块可以用来指定一段连续的IP地址范围,使用 起始IP地址-末尾IP地址 这样的格式。
匹配条件 | 说 明 |
---|---|
--src-range | 源地址范围 |
--dst-range | 目标地址范围 |
也很简单,如果想匹配目的地址为192.168.140.128到192.168.140.137之间,则可以使用:-m iprange --dst-range 192.168.140.128-192.168.140.137
。
④ string扩展模块
string扩展模块用来指定需要匹配的字符串,如果报文中包含对应的字符串,则符合匹配条件。
匹配条件 | 说 明 |
---|---|
--algo | 指定匹配算法,可选的算法有 bm 与 kmp,此选项为必须选项,不用纠结于选择哪个算法,但是必须指定一个 |
--string | 指定需要匹配的字符串 |
如果我们想匹配包含字符串"XXOO"的报文,就可以这样:-m string --algo bm --string "XXOO"
。
⑤ time扩展模块
time扩展模块用来根据时间段区匹配报文,如果报文到达的时间在指定的时间范围以内,则符合匹配条件。
匹配条件 | 说 明 |
---|---|
--timestart 时:分:秒 | 指定起始时间,比如 23:21:54 表示23时21分54秒 |
--timestop 时:分:秒 | 指定结束时间 |
--weekdays | 指定星期几,可以用1~7表示,也可以用缩写Mon, Tue, Wed, Thu, Fri, Sat, Sun表示 |
--datestart 年-月-日 | 指定起始日期 |
--datestop 年-月-日 | 指定结束日期 |
--monthdays | 指定每个月的哪一天 |
如果我们要匹配每周六、日的早上8点到下午1点,就可以这样:-m time --timestart 08:00:00 --timestop 13:00:00 --weekdays 6,7
。
其中,只有–monthdays与–weekdays可以使用" ! "取反,其他选项都不行哦。
⑥ connlimit扩展模块
connlimit扩展模块用于限制每个IP地址同时链接到服务端的链接数量。如果不指定IP,则默认针对每个IP地址进行限制。
匹配条件 | 说 明 |
---|---|
--connlimit-above | 限制链接数量上限 |
--connlimit-mask | 用于指定某类网段,与–connlimit-above配合使用,限制某类网段的链接数量 |
这里就需要先自行了解一些相关网络知识,接下来就来了解这个栗子。我们对一个C类网络中,同时最多只能有5个ssh客户端连接到当前服务器。在这里就需要大家明白为什么–connlimit-mask后所跟的参数是24呢?mask是掩码的意思,24转换成点分十进制为255.255.255.0,所以表示某个C类网段。
[root@localhost ~]# iptables -t filter -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 5 --connlimit-mask 24 -j ACCEPT
⑦ limit扩展模块
limit扩展模块用于对报文到达速率进行限制的,即限制单位时间内流入的包的数量,单位可以是秒、分钟、小时和天。
匹配条件 | 说 明 |
---|---|
--limit | 限制单位时间内流入数据包的数量,单位可以是秒、分钟、小时和天 |
--limit-burst | 设置令牌桶大小,默认为5 |
说到这里,就会有疑问,什么是令牌桶呢?大家可以这样理解:假如我们是这样设置的:-m limit --limit-burst 4 --limit 6/min
。桶里首先会放置4枚令牌,并且这个桶最多也只能放置4枚令牌,所有报文想通过关卡必须持有桶中的令牌。桶也有一个神奇的功能:每6秒会产生一个令牌。如果桶中的令牌有所消耗,那么新产生的令牌就会存放在桶中,反之如果桶中令牌是满的,那么新产生的令牌就会溢出木桶(被丢弃)。
#首先在IP为192.168.140.137的服务器上设置如下规则
[root@localhost ~]# iptables -t filter -I INPUT -p icmp -m limit --limit-burst 4 --limit 10/min -j ACCEPT
[root@localhost ~]# iptables -t filter -A INPUT -p icmp REJECT //默认规则是通行,所以设置该条拦截没有令牌的报文
#在另一台服务器上对192.168.140.137主机执行ping命令
[root@localhost123 ~]# ping 192.168.140.137
PING 192.168.140.137 (192.168.140.137) 56(84) bytes of data.
64 bytes from 192.168.140.137: icmp_seq=1 ttl=64 time=0.157 ms //放行 0 秒
64 bytes from 192.168.140.137: icmp_seq=2 ttl=64 time=0.274 ms //放行 1 秒
64 bytes from 192.168.140.137: icmp_seq=3 ttl=64 time=0.317 ms //放行 2 秒
64 bytes from 192.168.140.137: icmp_seq=4 ttl=64 time=0.504 ms //放行 3 秒
From 192.168.140.137 icmp_seq=5 Destination Port Unreachable //桶中已无令牌,拒绝 4 秒
From 192.168.140.137 icmp_seq=6 Destination Port Unreachable //桶中已无令牌,拒绝 5 秒
64 bytes from 192.168.140.137: icmp_seq=7 ttl=64 time=0.230 ms //产生新令牌,放行 6 秒
From 192.168.140.137 icmp_seq=8 Destination Port Unreachable //桶中已无令牌,拒绝 7 秒
From 192.168.140.137 icmp_seq=9 Destination Port Unreachable //桶中已无令牌,拒绝 8 秒
From 192.168.140.137 icmp_seq=10 Destination Port Unreachable //桶中已无令牌,拒绝 9 秒
From 192.168.140.137 icmp_seq=11 Destination Port Unreachable //桶中已无令牌,拒绝 10秒
From 192.168.140.137 icmp_seq=12 Destination Port Unreachable //桶中已无令牌,拒绝 11秒
64 bytes from 192.168.140.137: icmp_seq=13 ttl=64 time=0.493 ms //产生新令牌,放行 12秒
From 192.168.140.137 icmp_seq=14 Destination Port Unreachable //桶中已无令牌,拒绝 13秒
From 192.168.140.137 icmp_seq=15 Destination Port Unreachable //桶中已无令牌,拒绝 14秒
...省略部分内容
⑧ tcp模块之–tcp-flags
--tcp-flags模块是tcp扩展模块中的一个选项,它可以根据tcp头部标志位匹配报文,tcp包头中的标志位有6个:SYN,ACK,FIN,RST,URG,PSH。请同学务必了解相关tcp网络知识!!
匹配条件 | 说 明 |
---|---|
--tcp-flags | 匹配tcp头部标志位 |
如何匹配呢?举个栗子:-m tcp --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN
。我们可以看到后面的参数是两部分。
第一部分是SYN,ACK,FIN,RST,URG,PSH
,表示在该条规则中我们需要匹配tcp头部的6个标志位,所以可以理解为需要匹配的标志位。
第二部分是SYN
,表示在第一部分的标志位列表中,SYN标志位必须为1,其他标志位必须为0。所以可以理解为在第一部分的标志位列表中,哪些标志位必须为1。
上述的栗子还可以这样写:-m tcp --tcp-flags ALL SYN
,也就是说可以用ALL表示那六个标志位。
–syn 选项相当于--tcp-flags SYN,RST,ACK,FIN SYN
,所以我们可以用"–syn"选项匹配tcp连接的"第一次握手"。
⑨ state扩展模块
state扩展模块可以一个非常实用的模块,可以基于连接追踪机制匹配报文。什么是链接追踪呢?不论什么协议,客户端第一次访问时,服务器就会去内核内存中的追踪表查看他之前是否来过,查不到就证明是第一次来,记录入追踪表,如果查到以前来过,就不检查规则直接允许访问,这就叫做连接追踪机制。
其中共有5中状态:NEW 新建连接请求的数据包,第一次连接
ESTABLISHED NEW状态连接的回包,已建立的连接
INVALID 无法识别或没有任何状态的数据包
RELATED 当前数据包是一个新请求,但附属于某个已相关联的连接
UNTRACKED 一种特殊状态,管理员在raw表中为连接设置NOTRACK规则后的状态。
匹配条件 | 说 明 |
---|---|
--state | 基于连接追踪机制匹配报文 |
举个栗子,如何放行回应之前发出的报文?
#放行RELATED,ESTABLISHED两个状态的报文即可
[root@localhost ~]# iptables -t filter -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
⑩ udp扩展模块
udp扩展模块和tcp扩展模块大同小异,区别就是,udp扩展模块是用于匹配UDP协议报文的,并且只有两个选项。
匹配条件 | 说 明 |
---|---|
--sport port1[:prot2] | 匹配源端口 |
--dport port1[:prot2] | 匹配目的端口 |
看到上面选项参数的格式,大家肯定明白这两个选项可以指定单个或者一个连续的端口范围。那么是不是还能用multiport扩展模块指定多个离散的UDP端口呢?答案是肯定的!这里不做过多描述。
⑪ icmp扩展模块
icmp协议(Internet Control Message Protocol)译为"互联网控制报文协议"。它主要用于探测网络上的主机是否可用、目标是否可达、网络是否畅通和路由是否可用等,我们最常用的ping命令就使用的是icmp协议。
icmp报文从概念上可以分为多种type,而不同的type又可以分为多种code去应用具体的场景(具体看下图)。我们可以通过type/code或icmp报文的描述名称(英文)去匹配到具体的icmp报文。
如果我们想拒绝别的主机的ping请求,但不影响本机向别的主机发起ping请求,就可以通过这两种方法去设置:
iptables -t filter -I INPUT -p icmp --icmp-type 8/0 -j REJECT
iptables -t filter -I INPUT -p icmp --icmp-type "echo-request" -j REJECT
ping请求的type为8,code为0,所以别的主机发送的icmp报文将会被匹配到,但是为什么我们还能ping别人呢?这是因为本机的包发出并不经过INPUT链,并且当别的主机应答时,ping应答的type为0,code为0,所以并不会收到影响。
前面讲到,报文在经过iptables的链时会一一匹配链中的规则,如果匹配到则执行相应的动作。那么当一条报文没有被iptables中的规则所匹配时,就会执行链的默认策略(动作),这个默认策略通常设置为ACCEPT或DROP。
黑白名单也就是利用这种机制来实现的。可以这样来理解:
黑名单就是将默认策略设置为ACCEPT(把所有人当成好人,允许进入),链中的规则对应动作为DROP或REJECT(拒绝坏人进入)。也就是说只有匹配到规则的报文才会被拒绝,没有被规则匹配到的报文都会被默认允许。
白名单则是将默认策略设置为DROP(把所有人当成坏人,拒绝进入),链中的规则对应动作为ACCEPT(允许好人进入)。同理只有匹配到规则的报文才会被允许,没有被规则匹配到的报文都会被默认拒绝。
相对而言,白名单似乎安全性更高!具体如何实现呢?举个栗子:使用白名单机制,只放行ssh远程连接的相关报文。
[root@localhost ~]# iptables -t filter -I INPUT -p tcp --dport 22 -j ACCEPT //放行ssh远程连接的相关报文
[root@localhost ~]# iptables -P INPUT DROP //修改INPUT链默认策略为DROP
[root@localhost ~]# iptables -nL
Chain INPUT (policy `DROP`) //默认策略修改成功
target prot opt source destination
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:22
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
#此时如果手误执行了iptables -F,那么ssh工具还能远程连接到服务器上吗?试试便知。
[root@localhost ~]# iptables -F
[root@localhost ~]#
──────────────────────────────────────────────────────────────────────────────────────────────────────────
Session stopped
- Press <return> to exit tab
- Press R to restart session
- Press S to save terminal output to file
Network error: Software caused connection abort
所以说,要注意的是,默认策略设置为DROP这种做法不好!因为如果不小心清空了防火墙规则,那将导致所有数据包都无法进入,如果机器不在身边,管理员自己也就束手无策了!
可以以这种方式代替,我们仍然保持链的默认策略为ACCEPT,然后将“拒绝所有”这条规则放在链的尾部,将“放行规则”放在前面。这样做既可以实现白名单机制,又可以保证在规则被清空时不会被默认策略为DROP所影响。
之前我们所说到的防火墙分类中讲到,防火墙从逻辑上可以分为主机防火墙与网络防火墙,主机防火墙是针对于单个主机进行防护,而网络防火墙处于网络入口或边缘,针对网络入口进行防护,服务于防火墙背后的本地局域网。
上文的栗子中,iptables都是以主机防火墙的角色出现的。我们只用到了INPUT链和OUTPUT链,因为拥有"过滤功能"的链只有三条:INPUT、FORWARD、OUTPUT,当报文发往本机时,只能通过INPUT链和OUTPUT链进行过滤。而当iptables作为网络防火墙时,它的职责就变成了 过滤并转发 ,而想要转发,报文则只会经过它们中的FORWARD链。所以,iptables的角色变为"网络防火墙"时,规则只能定义在FORWARD链中。
下面就实现网络防火墙功能进行实验演示。
演示环境
— | 主机A | 主机B | 主机C |
---|---|---|---|
主机名 | localhost01 | localhost02 | localhost03 |
IP | eth0:192.168.140.129 | eth0:192.168.140.130 | |
eth1:192.168.38.130 | eth1:192.168.38.131 | ||
GETEWAY | 192.168.140.137 | 192.168.140.1,192.168.38.1 | 192.168.38.130 |
网卡模式 | NAT | eth0:NAT,eth1:仅主机 | 仅主机 |
#主机B作为192.168.38.0/24的网络防火墙,所以将主机C的网关指向主机B的eth1(内网)网卡IP
[root@localhost03 ~]# vim /etc/sysconfig/network-scripts/ifcfg-eth1
...省略部分内容
GETEWAY=192.168.38.130 //添加该条信息
#配置路由,将主机A访问192.168.38.0/24网络时的网关指向主机B的eth0(公网)网卡IP
[root@localhost01 ~]# route add -net 192.168.38.0/24 gw 192.168.140.130
[root@localhost01 ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.38.0 192.168.140.130 255.255.255.0 UG 0 0 0 eth0
192.168.140.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
0.0.0.0 192.168.140.2 0.0.0.0 UG 0 0 0 eth0
演示过程
#使用主机A向主机C发起ping请求
[root@localhost01 ~]# ping 192.168.38.131
PING 192.168.38.131 (192.168.38.131) 56(84) bytes of data.
^C
--- 192.168.38.131 ping statistics ---
296 packets transmitted, 0 received, 100% packet loss, time 295778ms
#可以看到主机A无法ping通主机C
#使用主机A向主机B发起ping请求
[root@localhost01 ~]# ping -c 4 192.168.140.130
PING 192.168.140.130 (192.168.140.130) 56(84) bytes of data.
64 bytes from 192.168.140.130: icmp_seq=1 ttl=64 time=0.143 ms
64 bytes from 192.168.140.130: icmp_seq=2 ttl=64 time=0.504 ms
64 bytes from 192.168.140.130: icmp_seq=3 ttl=64 time=0.438 ms
64 bytes from 192.168.140.130: icmp_seq=4 ttl=64 time=0.384 ms
--- 192.168.140.130 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 0.143/0.367/0.504/0.136 ms
#可以看到主机A可以ping通主机B内网IP
#那么192.168.38.130和192.168.38.131都属于一个网段,按道理都可以ping通,那么为什么ping主机C不通呢?
#主机A根据路由表的信息,将发往192.168.38.0/24网段的报文通通下跳给了192.168.140.130(主机B的外网网卡IP)
#当ping主机B的内网地址时,主机B发现自己便是目标主机,所以就回应了报文,这很好理解
#当ping主机C时,报文下跳到主机B时,主机B发现目标主机与自己是同一网段,这时就需要将这条报文转发给主机C
#但是在默认情况下,linux主机并不会转发报文,所以主机C没有收到报文,自然不会回应
#如何打开转发功能呢?很简单!
#临时生效
#方法一:
#查看/proc/sys/net/ipv4/ip_forward文件,如果文件中内容为0,表示当前主机不支持转发
[root@localhost02 ~]# cat /proc/sys/net/ipv4/ip_forward
0
#反之,如果文件中内容为1,表示当前主机支持转发。所以我们只需要修改该值为1即可。
[root@localhost02 ~]# echo 1 >> /proc/sys/net/ipv4/ip_forward
[root@localhost02 ~]# cat /proc/sys/net/ipv4/ip_forward
1
#方法二:
#使用sysctl命令
[root@localhost02 ~]# sysctl -w net.ipv4.ip_forward=0
net.ipv4.ip_forward = 0
[root@localhost02 ~]# cat /proc/sys/net/ipv4/ip_forward
0
[root@localhost02 ~]# sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
[root@localhost02 ~]# cat /proc/sys/net/ipv4/ip_forward
1
#永久生效
#CentOS6 配置/etc/sysctl.conf文件
#CentOS7 配置/usr/lib/sysctl.d/00-system.conf文件
#添加(或修改)配置项 net.ipv4.ip_forward = 1 即可
#此时再使用主机A向主机C发起ping请求,可以ping通
[root@localhost01 ~]# ping -c 4 192.168.38.131
PING 192.168.38.131 (192.168.38.131) 56(84) bytes of data.
64 bytes from 192.168.38.131: icmp_seq=1 ttl=64 time=0.214 ms
64 bytes from 192.168.38.131: icmp_seq=2 ttl=64 time=0.313 ms
64 bytes from 192.168.38.131: icmp_seq=3 ttl=64 time=0.493 ms
64 bytes from 192.168.38.131: icmp_seq=4 ttl=64 time=0.275 ms
--- 192.168.38.131 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3001ms
rtt min/avg/max/mdev = 0.214/0.323/0.493/0.106 ms
iptables上文讲到,iptables作为网络防火墙时,职责就变成了 过滤并转发 。而我们都知道 filter 表实现过滤,FORWARD链进行转发,所以就需要在filter表的FORWARD链中配置规则,从而达到网络防火墙的功能。
#实例目标:使主机A能访问主机C的web服务
#查看主机B的防火墙规则
[root@localhost02 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
#这里我们使用白名单机制,在主机B的iptables的FORWARD链末端添加一条默认拒绝的规则
[root@localhost02 ~]# iptables -t filter -A FORWARD -j REJECT
#打开主机C的httpd服务
[root@localhost01 ~]# service httpd start
#刚刚添加了默认拒绝的规则,主机A肯定无法访问主机C的web服务,现在我们在FORWARD链中添加一条允许外部主机A访问内部主机C的web服务的规则
[root@localhost02 ~]# iptables -t filter -I FORWARD -s 192.168.140.0/24 -p tcp --dport 80 -j ACCEPT
[root@localhost02 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
`ACCEPT tcp -- 192.168.140.0/24 0.0.0.0/0 tcp dpt:80`
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
#使用主机A访问主机C的web服务
[root@localhost01 ~]# curl 192.168.38.131
[root@localhost01 ~]#
#可以看到无法访问主机C的web服务,这是为什么呢?
#这是因为:主机B只放行了外部主机访问80端口的请求,但并没有放行内部主机的回应报文,所以没有反应
#知道了原因,我们需要在主机B添加一条允许回应报文通行的规则
[root@localhost02 ~]# iptables -t filter -I FORWARD -d 192.168.140.0/24 -p tcp --sport 80 -j ACCEPT
[root@localhost02 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
`ACCEPT tcp -- 0.0.0.0/0 192.168.140.0/24 tcp spt:80`
ACCEPT tcp -- 192.168.140.0/24 0.0.0.0/0 tcp dpt:80
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
#再次测试是否可以访问主机B的web服务
[root@localhost01 ~]# curl 192.168.38.131
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"><html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Apache HTTP Server Test Page powered by CentOS</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- Bootstrap -->
<link href="/noindex/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="noindex/css/open-sans.css" type="text/css" />
<style type="text/css"><!--
...省略部分内容
#测试成功
#在这里我们需要注意的是,在iptables作为网络防火墙,配置规则时往往需要考虑“双向性”。同时我们可以对上述实例规则配置进行优化
#使用--state模块,无论是由内向外,还是由外向内,只要是响应报文,我们统统放行
[root@localhost02 ~]# iptables -t filter -I FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
[root@localhost02 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
`ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED`
ACCEPT tcp -- 0.0.0.0/0 192.168.140.0/24 tcp spt:80
ACCEPT tcp -- 192.168.140.0/24 0.0.0.0/0 tcp dpt:80
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
#这样,即使后面有更多的服务需要对规则进行配置,回应报文都可以被上述这条规则所处理,而我们只需要考虑请求方即可
之前我们在定义规则时一直是在iptables中的默认链上定义的,当默认链中的规则非常多时,并不便与我们管理,那么就可以通过自定义链来解决问题。我们需要知道的是,自定义链并不能直接使用,而是需要被默认链引用才可以发挥自己的功能。下面大家从一个栗子来了解自定义链吧!
#创建一条自定义链对入站的web服务相关报文进行过滤
[root@localhost ~]# iptables -t filter -N IN_WEB //-N选项用来创建自定义链
[root@localhost ~]# iptables -nvL
Chain INPUT (policy ACCEPT 18 packets, 1152 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 9 packets, 856 bytes)
pkts bytes target prot opt in out source destination
Chain IN_WEB (0 references) //创建成功
pkts bytes target prot opt in out source destination
#在自定义链中配置规则:拒绝源地址为192.168.38.0/24的网络访问web服务
[root@localhost ~]# iptables -t filter -I IN_WEB -s 192.168.38.0/24 -j REJECT
[root@localhost ~]# iptables -nvL
Chain INPUT (policy ACCEPT 13 packets, 808 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 8 packets, 784 bytes)
pkts bytes target prot opt in out source destination
Chain IN_WEB (0 references)
pkts bytes target prot opt in out source destination
0 0 REJECT all -- * * 192.168.38.0/24 0.0.0.0/0 reject-with icmp-port-unreachable
#现在自定义链中虽然有规则,但是无法匹配报文,因为我们还没有在任何默认链中引用它
#即为web服务的入站规则所创建,那么毋庸置疑需要用INPUT链去引用它
[root@localhost ~]# iptables -I INPUT -p tcp --dport 80 -j IN_WEB
[root@localhost ~]# iptables -nvL
Chain INPUT (policy ACCEPT 6 packets, 384 bytes)
pkts bytes target prot opt in out source destination
0 0 IN_WEB tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 3 packets, 296 bytes)
pkts bytes target prot opt in out source destination
Chain IN_WEB (`1 references`)
pkts bytes target prot opt in out source destination
0 0 REJECT all -- * * 192.168.38.0/24 0.0.0.0/0 reject-with icmp-port-unreachable
#上述这条规则表示:访问本机80端口的tcp报文会由自定义链"IN_WEB"中的规则进行处理。
#之前讲到-j选项后面指定处理动作,在这里变成了自定义链,这种情况就表示当前匹配到的报文交由对应的自定义链处理,具体得取决于自定义链中的规则
#同时也可以看到,IN_WEB链高亮字体,表示引用次数,这里已经变成1了呢
#过一段时间,如果我们觉得这个名字不够帅,想改一个,怎么办呢?
[root@localhost ~]# iptables -E IN_WEB COOL_CHAIN //-E选项用来重命名自定义链
[root@localhost ~]# iptables -nvL
Chain INPUT (policy ACCEPT 6 packets, 384 bytes)
pkts bytes target prot opt in out source destination
0 0 COOL_CHAIN tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:80
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 4 packets, 400 bytes)
pkts bytes target prot opt in out source destination
Chain COOL_CHAIN (1 references)
pkts bytes target prot opt in out source destination
0 0 REJECT all -- * * 192.168.38.0/24 0.0.0.0/0 reject-with icmp-port-unreachable
#可以看到,引用自定义链处的名称自动会发生修改
#现在我们来探讨如何删除自定义链
#想要删除自定义链,需要满足两个条件:
# ① 自定义链没有被任何默认链引用,也就是说引用计数为0
# ② 自定义链中没有任何规则,也就是说自定义链为空
#现在我们来看看不满足条件的情况是什么样的
[root@localhost ~]# iptables -X COOL_CHAIN
iptables: Too many links. //提示你太多链接哦!不满足条件①的哦!
[root@localhost ~]# iptables -D INPUT 1 //删除引用
[root@localhost02 ~]# iptables -X COOL_CHAIN
iptables: Directory not empty. //提示你链不为空哦!不满足条件②的哦!
[root@localhost ~]# iptables -F COOL_CHAIN
[root@localhost ~]# iptables -X COOL_CHAIN //再次尝试删除自定义链
[root@localhost ~]# iptables -nvL //删除成功
Chain INPUT (policy ACCEPT 32 packets, 2144 bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 19 packets, 1704 bytes)
pkts bytes target prot opt in out source destination
之前我们只了解到一些处理动作的基础知识,其实处理动作也有自己的选项。
REJECT动作的常用选项为–reject-with,可以设置提示信息,当对方被拒绝时,会提示对方为什么被拒绝。有这些可用的值:
选 项 | 描 述 |
---|---|
icmp-net-unreachable | 网络不可达 |
icmp-host-unreachable | 主机不可达 |
icmp-port-unreachable | 端口不可达,默认值 |
icmp-proto-unreachable | 协议不可达 |
icmp-net-prohibited | 网络被禁止 |
icmp-host-pro-hibited | |
icmp-admin-prohibited |
给大家举个栗子:
演示环境
— | 主机A | 主机B |
---|---|---|
主机名 | localhost01 | localhost02 |
IP | eth0:192.168.140.130 | eth1:192.168.140.131 |
演示过程
#在主机A上设置规则:拒绝来自主机B的报文,不使用任何选项
[root@localhost01 ~]# iptables -t filter -I INPUT -s 192.168.140.131 -j REJECT
[root@localhost01 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target prot opt source destination
REJECT all -- 192.168.140.131 0.0.0.0/0 reject-with icmp-port-unreachable
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
[root@localhost02 ~]# ping -c 4 192.168.140.130 //可以看到,当没有明确设置--reject-with的值时,默认提示信息为icmp-port-unreachable
PING 192.168.140.130 (192.168.140.130) 56(84) bytes of data.
From 192.168.140.130 icmp_seq=1 Destination Port Unreachable
From 192.168.140.130 icmp_seq=2 Destination Port Unreachable
From 192.168.140.130 icmp_seq=3 Destination Port Unreachable
From 192.168.140.130 icmp_seq=4 Destination Port Unreachable
--- 192.168.140.130 ping statistics ---
4 packets transmitted, 0 received, +4 errors, 100% packet loss, time 3001ms
[root@localhost01 ~]# iptables -t filter -D INPUT 1 //删除规则
#在主机A上设置规则:拒绝来自主机B的报文,设置提示信息为"网络不可达"
[root@localhost01 ~]# iptables -t filter -I INPUT -s 192.168.140.131 -j REJECT --reject-with icmp-net-unreachable
[root@localhost01 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target prot opt source destination
REJECT all -- 192.168.140.131 0.0.0.0/0 reject-with icmp-net-unreachable
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
[root@localhost02 ~]# ping -c 4 192.168.140.130 //提示信息已经变为icmp-Net-Unreachable
PING 192.168.140.130 (192.168.140.130) 56(84) bytes of data.
From 192.168.140.130 icmp_seq=1 Destination Net Unreachable
From 192.168.140.130 icmp_seq=2 Destination Net Unreachable
From 192.168.140.130 icmp_seq=3 Destination Net Unreachable
From 192.168.140.130 icmp_seq=4 Destination Net Unreachable
--- 192.168.140.130 ping statistics ---
4 packets transmitted, 0 received, +4 errors, 100% packet loss, time 3000ms
LOG动作可以将匹配到的报文的相关信息记录到日志(/var/log/messages文件)中,但不对报文做任何处理。举个栗子:
演示环境
— | 主机A | 主机B |
---|---|---|
主机名 | localhost01 | localhost02 |
IP | eth0:192.168.140.130 | eth1:192.168.140.131 |
演示过程
#在主机A上设置规则:将B主机发往本机的报文的相关信息记录在日志中
[root@localhost01 ~]# iptables -t filter -I INPUT -s 192.168.140.131 -j LOG
[root@localhost01 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target prot opt source destination
LOG all -- 192.168.140.131 0.0.0.0/0 LOG flags 0 level 4
Chain FORWARD (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
[root@localhost02 ~]# ping -c 1 192.168.140.130 //向主机A发送ping包
[root@localhost01 ~]# cat /var/log/messages //对应报文的相关信息已经被记录在日志中
Jun 15 11:13:57 localhost kernel: IN=ens33 OUT= MAC=00:0c:29:50:a7:c5:00:0c:29:62:76:53:08:00 SRC=192.168.140.131 DST=192.168.140.130 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=20711 DF PROTO=ICMP TYPE=8 CODE=0 ID=8168 SEQ=1
当然,我们也可以将相关信息记录在指定的文件中,如果企业有专门的日志服务器,这些日志就可以分类管理。
#在/etc/rsyslog.conf文件中进行配置即可
[root@localhost01 ~]# vi /etc/rsyslog.conf
...省略部分内容
kern.warning /var/log/ping.log
[root@localhost ~]# systemctl restart rsyslog //完成配置后需要重启服务才可生效
[root@localhost ~]# ping -c 1 192.168.140.130 //再次向主机A发送ping包
[root@localhost ~]# cat /var/log/ping.log
2020-06-15T11:24:40.801886+08:00 localhost kernel: IN=ens33 OUT= MAC=00:0c:29:50:a7:c5:00:0c:29:62:76:53:08:00 SRC=192.168.140.131 DST=192.168.140.130 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=37823 DF PROTO=ICMP TYPE=8 CODE=0 ID=8171 SEQ=1
LOG动作也有一些选项,常用的有这些:
选 项 | 描 述 |
---|---|
–log-level | 指定记录日志的日志级别,可用级别有emerg、alert、crit、error、warning、notice、info、debug |
–log-prefix | 给所记录的信息添加"标签",以便区分各种所记录的报文的信息,对应的值不能超过29个字符 |
对这两个选项不做过多描述。需要提一点,在使用LOG动作时,如果匹配条件很广泛,那么匹配到的报文就越多,记录的信息就会很复杂,当你查看时便会摸不着头脑。所以说,匹配条件尽可能精确一些,这样日志中的信息冗余就会更少,分析起来效率更高呢!
NAT(Network Address Translation),译为"网络地址转换"。通俗来说,也就是修改报文的IP地址,通常NAT功能会被集成到路由器、防火墙、或独立的NAT设备中。
那么修改报文的IP地址该应用于哪些实际场景呢?比如公司的局域网里每个员工的机器都是私有IP,只能在局域网内的互相访问,公网无法访问到这些私有IP,整个公司只有一个可用的公网IP,那么如何与公网的服务器交互呢?又比如内网的主机访问其他网络中的主机时,会暴露自己的IP地址,那么如何隐藏这些主机的IP地址呢?
我们只需要在路由器上配置公网IP,在私网主机访问公网服务时,报文经过路由器时,报文中的私网IP和端口号就会换成公网IP和端口号。这样内网主机可以共享公网IP访问互联网了,与此同时,外部主机收到报文时,源地址和源端口显示的都是公网IP和端口,当外部主机回应时,路由器会根据NAT表的映射记录,将回应报文的目标IP和目标端口换成内部主机的IP和端口,然后再将回应报文发给内网中对应的主机。
其实整个过程实际有两次地址转换:
①内部主机的报文发送出去时,报文的源IP和端口发生了改变,也就是源地址转换(SNAT)。
②外部主机回应报文后,响应报文的目标IP和端口发生了改变,也就是目标地址转换(DNAT)。
上述过程被称为SNAT,那大家肯定会有疑问,整个过程SNAT和DNAT都有,为什么叫SNAT呢?其实这个取决于整个过程的上半段使用的是什么!
接下来举个栗子,看看规则应该如何配置吧!
演示环境
— | 主机A(外网主机) | 主机B(防火墙) | 主机C(公司web服务器) |
---|---|---|---|
主机名 | localhost01 | localhost02 | localhost03 |
IP | eth0:192.168.140.129 | eth0:192.168.140.130(公网) | |
eth1:192.168.38.130(私网) | eth1:192.168.38.131 | ||
GETEWAY | 192.168.140.137 | 192.168.140.1,192.168.38.1 | 192.168.38.130 |
网卡模式 | NAT | eth0:NAT,eth1:仅主机 | 仅主机 |
作为防火墙的主机负责对报文的修改与转发,所以,需要开启核心转发功能。
演示过程
#SNAT 将来自于192.168.38.0/24网段(内网)的报文的源地址改为公司的公网IP地址
[root@localhost02 ~]# iptables -t nat -I POSTROUTING -s 192.168.38.0/24 -j SNAT --to-source 192.168.140.130
[root@localhost02 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
SNAT all -- 192.168.38.0/24 0.0.0.0/0 to:192.168.140.130
---------------------------------------------------------------------------------
#DNAT 将访问公网IP的80端口的报文的目标地址改为公司web服务器的IP的80端口
[root@localhost02 ~]# iptables -t nat -I PREROUTING -d 192.168.140.130 -p tcp --dport 80 -j DNAT --to-destination 192.168.38.131:80
[root@localhost02 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DNAT tcp -- 0.0.0.0/0 192.168.140.130 tcp dpt:80 to:192.168.38.131:80
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
SNAT all -- 192.168.38.0/24 0.0.0.0/0 to:192.168.140.130
MASQUERADE与NAT很类似,它会动态地将源地址转换为可用的IP地址。当我们使用拨号上网,那么每次会分配不同的IP地址。如果这种情况下想让内网主机共享公网IP上网,那么每次都要重新配置SNAT规则,这样无疑是很麻烦的!这时就可以通过MASQUERADE解决,它不需要指明确定的IP,会动态地将报文的源地址修改为指定网卡上可用的IP地址。举个栗子:
[root@localhost02 ~]# iptables -t nat -I POSTROUTING -s 192.168.38.131 -o ens33 -j MASQUERADE
[root@localhost01 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 192.168.38.131 0.0.0.0/0
REDIRECT动作可以在本机上进行端口映射。经过映射,当别的机器访问本机的特定端口时,报文会被重定向到本机的指定端口上。REDIRECT动作只能定义在PREROUTING链和OUTPUT链中。举个栗子:
#将本机的80端口映射到本机的8080端口上
[root@localhost ~]# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
[root@localhost ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
REDIRECT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 redir ports 8080
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain POSTROUTING (policy ACCEPT)
target prot opt source destination
#设置完成后,当其他机器访问本机的80端口时,报文会被重定向到本机的8080端口上
一些叙述可能不太准确,但是希望可以帮助到大家!如果其中有错误,还希望能及时告知我!谢谢大家!