Iptables防火墙的简单使用

469 阅读1小时+

说明

在CentOS7中,已经用firewalld来代替iptables了,但是iptables命令还是存在的。

很多人并不习惯使用firewalld来配置防火墙,所以如果要CentOS7要使用iptables取代friewalld,需要自行安装:

# 停止并取消firewald开机自启
systemctl stop friewalld.service
systemctl disable firewalld.service

# 安装iptables服务
yum install -y iptables-services

# 启动并设置iptables开机自启
systemctl start iptables.service
systemctl enable iptables.service

1.1 Iptables基础

1.1.1 什么是防火墙?

  • 过去很长一段时间中,我们的房屋都是草木结构,如果一家失火,四邻也会跟着遭殃,所以为了安全起见,古人就在自己居住地周围修筑高高的围墙,以阻挡外来的火势,保护自家安全,这种墙就叫防火墙
  • 现今,因特网把世界各地的计算机都紧密连接在一起。如果不严加防卫,一旦网络被侵害,可能会出现不可预计的损失。那么在互联网上,我们会采取类似防火墙的方法,来保护我们自己的计算机不被侵害,为此我们需要设定防火墙规则,确定哪些类型的数据包允许被防火墙放行,哪些则不被防火墙放行。那么,具备这种功能的设备或者软件就可以称之为防火墙
  • 防火墙(英语:Firewall)技术是通过有机结合各类用于安全管理与筛选的软件硬件设备,帮助计算机网络于其内、外网之间构建一道相对隔绝的保护屏障,以保护用户资料与信息安全性的一种技术。
  • 防火墙技术的功能主要在于及时发现并处理计算机网络运行时可能存在的安全风险、数据传输等问题,其中处理措施包括隔离与保护,同时可对计算机网络安全当中的各项操作实施记录与检测,以确保计算机网络运行的安全性,保障用户资料与信息的完整性,为用户提供更好、更安全的计算机网络使用体验。

1.1.2 防火墙种类

  • 从逻辑上来讲,防火墙可以大体分为主机防火墙和网络防火墙

    • 主机防火墙:针对单台主机进行防护,比如个人电脑上的防火墙。
    • 网络防火墙:这种防火墙往往处于网络入口处,针对网络入口进行防护,服务于防火墙背后的服务器集群。

    网络防火墙和主机防火墙并不冲突,可以理解为,网络防火墙主外(集体), 主机防火墙主内(个人)。

  • 从物理上来讲,防火墙可以分为硬件防火墙软件防火墙

    • 硬件防火墙:在硬件级别实现部分防火墙功能,另一部分功能基于软件实现,性能高,成本高。
    • 软件防火墙:以软件的方式模拟防火墙功能,运行在操作系统之上,性能不高,成本低。

1.1.3 什么是Iptables?

  • iptables其实不是真正的防火墙,我们可以把它理解成一个客户端代理,用户通过iptables这个代理,将用户的安全设定执行到对应的安全框架中,这个安全框架才是真正的防火墙,这个框架的名字叫netfilter
  • netfilter才是防火墙真正的安全框架,netfilter位于内核空间,是内核代码中不可或缺的一部分,而iptables其实是一个命令行工具,位于用户空间,我们通过iptables这个工具来操作netfilter这个安全框架。
  • 所以Iptables的完整叫法应该是netfilter/iptables,它是Linux平台下的包过滤型防火墙,这个包过滤防火墙是免费的,它可以替代昂贵的防火墙解决方案,完成数据包过滤连接追踪限速网络地址转换NAT(Network Address Translate)封包过滤封包重定向等功能。

image-20220210160523228

1.1.4 什么是包过滤防火墙

  • 包过滤型防火墙它工作在OSI七层模型中的网络层,用来匹配网络数据包的(Header)。
    1. Header与预先定义好的防火墙规则进行比对
    2. 与规则匹配的包会被放行
    3. 与规则不匹配的包可能会被丢弃,也可能执行其他更复杂的操作
  • 由于包过滤型防火墙工作在网络层,故也称作网络层防火墙,它检查每一个数据包的:
    • 源地址、目标地址
    • 源端口、目标端口
    • 协议类型(TCP、UDP、ICMP)等状态信息来判断是否符合规则

1.1.5 包过滤防火墙如何实现

  • 包过滤防火墙是由Netfilter来实现的,它是内核的一部分
  • iptables是按照规则来办事的,我们就来说说规则(rules),规则其实就是网络管理员预定义的条件,规则一般的定义为”如果数据包头符合这样的条件,就这样处理这个数据包”。规则存储在内核空间的信息包过滤表中,这些规则分别指定了源地址、目的地址、传输协议(如TCP、UDP、ICMP)和服务类型(如HTTP、FTP和SMTP)等。当数据包与规则匹配时,iptables就根据规则所定义的方法来处理这些数据包,如放行(accept)、拒绝(reject)和丢弃(drop)等。配置防火墙的主要工作就是添加、修改和删除这些规则。
  • 防火墙要实现"防火"的目的,则需要预先在内核中设置关卡,所有进出的报文都需要经过这些关卡检查:
    • 符合条件的放行
    • 不符合条件的丢弃,或者进行其他操作
    • 这些关卡在iptables中不被称为关卡,而被叫做

1.2 IPtables表、链、规则

1.2.1 Iptables链的概念

1.2.1.1 什么是链?
  • iptables中的关卡为什么被称作呢?
  • 防火墙的作用就在于对经过的数据报文进行规则匹配,然后执行规则对于的动作,所以当报文经过这些关卡的时候,必须要匹配这个关卡的规则,但是这个关卡上可能不止有一个规则,往往是由很多规则,当我们把这些规则串起来之后,就形成了
  • 所以,每个经过这个"关卡"的报文,都要将这个链上的所有规则匹配一遍,如果有符合条件的规则,则执行规则对于的动作,如果没有匹配到规则,则执行该链的默认动作。

image-20220210164309006

1.2.1.2 Iptables有哪些链
  • 当我们启动防火墙功能时,报文需要经过很多"关卡",根据不同的情况,报文经过的可能不同,大体分为如下三类:
    • 到本机的报文:PREROUTING > INPUT
    • 由本机转发的报文:PREROUTING > FORWARD > POSTROUTING
    • 本机发出的报文:OUTPUT > POSTROUTING
  • 了解Iptables链的数据包流向;后期在设定规则时,能够很清晰的知道将规则设置在哪个链上

image-20220210165823840

1.2.2 Iptables表的概念

1.2.2.1 什么是表?
  • 我们在每一个上都放置了很多的规则,但是这些规则有些很相似,比如:

    • A类规则都是对IP或者端口的过滤
    • B类规则都是对报文进行修改
    • C类规则都是进行地址转换

    那么这时候,我们是不会应能够将实现相同功能的规则放在一起比较呢?

  • 我们把具有相同功能的规则的集合叫做,不同功能的规则,我们可以放在不同的表中进行管理,而Iptables已经为我们预先定义了4种表,每种表对应了不同的功能,而我们自己定义的规则也都逃脱不了这4种功能的范围。

1.2.2.2 表的功能

Iptables为我们提供了如下规则分类,或者说,Iptables为我们提供了如下的

表名作用包含的链内核模块
filter负责过滤功能INPUT、OUTPUT、FORWARDiptable_filter
nat负责网络地址转换PREROUTING、INPUT、OUTPUT、POSTROUTINGiptable_nat
mangle拆解报文,做出修改,并重新封装INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTINGiptable_mangle
raw关闭nat表上启用的连接追踪机制PREROUTING、OUTPUTiptable_raw

也就是说,我们自定义的所有规则,都是这四种分类中的规则,或者说,所有规则都在这四张中。

1.2.2.3 表的优先级

Iptables为我们定义了四张表,当四张表处于同一条链时,执行的优先级如下:

优先级由高到低:raw > mangle > nat > filter

1.2.2.4 表与链的关系
  • 某些链因为要实现特定的功能注定不会包含某些表
  • 链和表的关系:
    • PREROUTING链可以包含的表:raw、mangle、nat
    • INPUT链可以包含的表:mangle、filter、nat(CentOS7中有,CentOS6没有)
    • FORWARD链可以包含的表:mangle、filter
    • OUTPUT链可以包含的表:raw、mangle、nat、filter
    • POSTROUTING链可以包含的表:mangle、nat
  • 实际使用中,往往是通过表作为操作入口,来对规则进行定义
  • 表和链的关系:
    • raw表规则可以使用的链:PREROUTING、OUTPUT
    • mangle表规则可以使用的链:PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING
    • nat表规则可以使用的链:PREROUTING、INPUT(CentOS7中有,CentOS6中没有)、OUTPUT、POSTROUTING
    • filter表规则可以使用的链:INPUT、FORWARD、OUTPUT
  • 数据包经过一个链的时候,按照表规则匹配优先级进行匹配,匹配到规则之后执行对应的动作,就不会继续向后匹配,如果没有匹配到规则,则执行链的默认动作

image-20220210181545707

image-20220211104119343

1.2.2.5 表与链相关问题

对于防火墙规则,在越前面的链上做越好。

  • 问题1:来自10.0.0.1的地址,访问本机的web服务请求不允许,应该在哪个表和哪个链上设置规则?
    • filter表 INPUT链,因为这里是要做过滤的规则,所以肯定是filter表,但是PREROUTING链上没有fliter表,所以只能在INPUT
  • 问题2:本机所有发往10.0.0.0/24网段的TCP请求都不允许,应该在哪个表和哪个链上设置规则?
    • filter表 OUTPUT链,因为这里是要做过滤的规则,所以肯定是filter表,但是POSTROUTING链上没有fliter表,所以只能在OUTPUT
  • 问题3:所有来自本地内部网络的主机,都允许向互联网发送请求,应该在哪个表和哪个链上设置规则?
    • filter表 FORWARD链,因为这里是要做过滤的规则,所以肯定是filter表,转发请求,要通过PREROUTINGFORWARDPOSTROUTING三条链,但是PREROUTINGPOSTROUTING链上没有fliter表,所以只能在FORWARD

1.2.3 Iptables规则管理

1.2.3.1 什么是规则?
  • 数据包的过滤基于规则进行,而规则是由匹配条件动作组成的。那么对规则的操作无非就是增删改查。

  • 匹配条件:

    • 基本匹配条件:
      • 源地址:Source IP
      • 目标地址:Destination IP

    除了上述的条件可以用于匹配,还有很多其他的条件可以用于匹配,这些条件泛称为扩展条件,这些扩展条件其实也是netfilter中的一部分,只是以模块的形式存在,如果想要使用这些条件,则需要依赖对应的扩展模块。

    • 扩展匹配条件:
      • 源端口:Source Port
      • 目标端口:Destination Port
  • 动作:处理动作也分为基本动作和扩展动作,下面列出一些常用的动作:

    • ACCEPT:允许数据包通过
    • DROP:直接丢弃数据包,不给任何回应信息,这时候客户端会感觉自己的请求泥牛入海了,过了超时时间才会有反应
    • REJECT:拒绝数据包通过,必要时会给数据发送端一个响应信息,客户端刚请求就会收到拒绝信息
    • SNAT:源地址转换,解决内网用户用同一个公网地址上网的问题
    • MASQUERADE:是SNAT的一种特殊形式,适用于动态的、临时会变的ip上
    • DNAT:目标地址转换
    • REDIRECT:在本机做端口映射
    • LOG:在/var/log/message文件中记录日志信息,然后将数据包传递给下一条规则,也就是说除了记录以外不对数据包做任何其他操作,仍然让下一条规则去匹配
  • 操作规则语法:

    iptables [-t 表名] 选项 [链名] [规则] [动作]
    
  • 操作规则之前我们需要考量如下两个问题:

    1. 要实现什么功能:判断在哪个表上设置规则
    2. 报文流经的链路顺序:判断在哪个链上设置规则
iptables选项含义示例
-t,--table指定要操作的表,默认是filteriptables -t filter
-A,--append追加一条规则至链的尾部iptables -t filter -A INPUT
-I,--insert插入一条规则至链的顶部iptables -t filter -I input
-D,--delete指定删除一条规则iptables -t filter -D INPUT 1
-R,--replace替换选定链中的规则iptables -t filter -R INPUT
-S,--list-rules打印选定链中的所有规则iptables -t filter -S
-F,--flush清空链中的所有规则iptables -t filter -F-
-Z,--zero将所有链中的数据包和字节计数器归零iptables -t filter -Z
-N,--new-chain创建自定义规则链iptables -N New_Rules
-E,--rename-chain给自定义链修改名称iptables -E Old_Rules New_Rules
-X,--delete-chain删除自定义链iptables -X Rules_Name
-P,--policy给链设定默认策略iptables -t filter -P DROP
1.2.3.2 如何查看规则
  • -t:指定要操作的表名称
  • -L:查看该表的详细信息
  • -n:不解析IP地址
  • -v显示详细信息
  • -x:显示计数器精确值
  • --line-numbers:显示没跳规则在该表中的序号
# 查看filter表的规则
iptables -t filter -L
iptables -L  # 不加-t指定表名的时候,默认都是filter表

# 查看nat表的规则
iptables -t nat -L

# 不解析IP
iptables -L -n

# 显示详细信息
iptables -L -n -v

# 显示计数器精确值
iptables -L -n -v -x

# 显示规则在表中的序号(操作规则有时候需要序号,比如修改规则的时候)
iptables -L -n -v --line-numbers
iptables -L -n -v --line  # –line-numbers选项并没有对应的短选项,不过我们缩写成–-line时,centos中的iptables也可以识别

# 为了书写简洁,多个参数可以合并
iptables -t filter --line -nvxL

# 查看某条链某个表的规则
iptables -t filter --line -nvxL INPUT

-n参数不解析IP地址:-n参数不解析IP地址

上图中的第一条命令执行后源地址与目标地址都为anywhere,iptables默认为我们进行了名称解析,但是在规则非常多的情况下如果进行名称解析,效率会比较低,所以,在没有此需求的情况下,我们可以使用-n选项,表示不对IP地址进行名称反解,直接显示IP地址。

-v参数显示更加详细的信息:-v参数显示更加详细的信息

各个参数的含义:

  • pkts:对应规则匹配到的报文的个数。
  • bytes:对应匹配到的报文包的大小总和。
  • target:规则对应的target,往往表示规则对应的动作,即规则匹配成功后需要采取的措施。
  • prot:表示规则对应的协议,是否只针对某些协议应用此规则。
  • opt:表示规则对应的选项。
  • in:表示数据包由哪个接口(网卡)流入,我们可以设置通过哪块网卡流入的报文需要匹配当前规则。
  • out:表示数据包由哪个接口(网卡)流出,我们可以设置通过哪块网卡流出的报文需要匹配当前规则。
  • source:表示规则对应的源头地址,可以是一个IP,也可以是一个网段。
  • destination:表示规则对应的目标地址。可以是一个IP,也可以是一个网段。

--line-numbers显示规则在表中的序号:--line-numbers显示规则在表中的序号

表中的每个链的后面都有一个括号,括号里面有一些信息,如下图红色标注位置,那么这些信息都代表了什么呢?image-20220211144517177

  • policy表示当前链的默认策略,policy ACCEPT表示上图中INPUT的链的默认动作为ACCEPT,换句话说就是,默认接受通过INPUT关卡的所有请求,所以我们在配置INPUT链的具体规则时,应该将需要拒绝的请求配置到规则中,说白了就是”黑名单”机制,默认所有人都能通过,只有指定的人不能通过,当我们把INPUT链默认动作设置为接受(ACCEPT),就表示所有人都能通过这个关卡,此时就应该在具体的规则中指定需要拒绝的请求,就表示只有指定的人不能通过这个关卡,这就是黑名单机制。
  • packets表示当前链(上例为INPUT链)默认策略匹配到的包的数量,1534 packets表示默认策略匹配到1534个包。
  • bytes表示当前链默认策略匹配到的所有包的大小总和。

其实,我们可以把packets与bytes称作”计数器”,上图中的计数器记录了默认策略匹配到的报文数量与总大小,”计数器”只会在使用-v选项时,才会显示出来。

当被匹配到的包达到一定数量时,计数器会自动将匹配到的包的大小转换为可读性较高的单位(比如K, M等单位)。

如果你想要查看精确的计数值,而不是经过可读性优化过的计数值,那么你可以使用-x选项,表示显示精确的计数值,示例如下。image-20220211145047234

每张表中的每条链都有自己的计数器,链中的每个规则也都有自己的计数器,没错,就是每条规则对应的pkts字段与bytes字段的信息。

1.2.3.3 如何添加规则
  • -t:指定表名
  • -I:插入一条规则在链的顶部
  • -A:追加一条规则在链的尾部
  • -p:指定需要匹配的协议,如icmp、tcp、udp等
  • 更多参数会在下文iptables匹配参数中说明

本机IP为:192.168.126.150:image-20220211145954588

默认情况下是可以被ping通的:image-20220211150125606

添加iptables规则,使得本机禁ping:

# 添加一条规则,将本机禁ping
iptables -t filter -I INPUT -p icmp -j REJECT

image-20220211150307710

然后在另一台主机上ping该主机:image-20220211150351822

既然已经实现了禁ping,那如果在追加一条规则接收所有的icmp协议请求呢?

iptables -A INPUT -p icmp -j ACCEPT  # 不使用-t参数指定表名,默认就是filter表

image-20220211150744731

然后在另一台主机上ping该主机:![image-20220211150842000](/Users/staryjie/Library/Application Support/typora-user-images/image-20220211150842000.png)

显然,还是ping不通的,这就和iptables中数据包的流向和规则匹配机制有关了,因为这条规则在REJECT的规则之后,数据包匹配到REJECT之后执行了REJECT动作,就不会继续匹配后面的规则了。所有ACCEPT这个动作的规则不会被匹配到。

那么只要将ACCEPT动作的规则放在REJECT动作的规则之前就可以ping通了:

iptables -I INPUT -p icmp -j ACCEPT

image-20220211151237301

此时再次ping该主机:image-20220211151317282

1.2.3.4 如何修改规则
  • -R:修改指定的规则,必须知道要修改的规则在对应表中的序号

修改上一步中REJECT动作的规则的动作为DROP:

iptables -t filter -F INPUT  # 先清空对应的规则,防止其他规则干扰
iptables -t filter -I INPUT -p icmp -j REJECT  # 恢复REJECT动作的规则

# 获取要修改的规则的序号
iptables --line -nvxL

image-20220211151833159

已知这个要修改的规则的序号为1,此时是无法ping通的,效果如下:image-20220211152018065

因为此时的动作为REJECT,拒绝,所以ping的返回信息为Destination Port Unreachable

# 修改REJECT动作为DROP
iptables -t filter -R INPUT 1 -p imcp -j DROP

image-20220211152150400

这时候已经把动作从REJECT改为DROP了,再次ping之后的效果是这样的:image-20220211152320965

REJECT改为DROP之后,ping无任何返回信息,直到超时之后显示最终结果。

注意:使用规则序号对规则进行修改的时候,务必要在修改的时候将原先的匹配条件完整的书写上,不然一些涉及源IP、目标IP、源端口、目标端口等的条件会发生改变,比如源IP和目标IP会变成0.0.0.0/0

既然使用-R选项修改规则时,必须指明规则原本的匹配条件,那么我们则可以理解为,只能通过-R选项修改规则对应的动作了,所以我觉得,如果你想要修改某条规则,还不如先将这条规则删除,然后在同样位置再插入一条新规则,这样更好,当然,如果你只是为了修改某条规则的动作,那么使用-R选项时,不要忘了指明规则原本对应的匹配条件。

1.2.3.5 如何删除规则
  • -D:删除指定规则,必须知道要删除的规则在对应表中的编号或者具体的匹配条件和动作
1.2.3.5.1 根据规则编号删除规则
# 删除修改为DROP动作的规则,上一步已经知道它的序号为1
iptables --line -nvxL
iptables -t filter -D INPUT 1

删除规则之后:image-20220211152613648

再次ping,结果如下:image-20220211152737959

1.2.3.5.2 根据具体匹配条件和动作删除规则
# 先插入一条规则
iptables -t filter -I INPUT -p tcp -s 192.168.126.39 -j DROP

# 查看规则
iptables --line -nvxL

# 删除规则
iptables -t filter -D INPUT -p tcp -s 192.168.126.39 -j DROP

根据具体匹配规则和动作删除规则:image-20220211160126441

1.2.3.6 如何保存规则
1.2.3.6.1 service iptables save

iptables的规则在主机重启之后就会丢失,那么我们应该定时通过service iptables save命令把iptables规则备份一下,重启之后可以及时恢复iptables规则。

在CentOS6.x和CentOS7.x中,都可以通过service iptables save来保存规则,规则默认保存在/etc/sysconfig/iptables文件中。

# 先设置几条规则
iptables -t filter -I INPUT -p icmp -j REJECT
iptables -t filter -I INPUT -p tcp -s 192.168.126.39 -j DROP

# 查看规则
iptables --line -nvxL
iptables-save  # 将内核中的规则打印到标准输出,要备份的话可以通过重定向到文件实现

# 备份规则
service iptables save
iptables-save > /etc/iptables-20220211.rule

# 备份指定表的规则,-c表示输出中显示每条规则当前报文的技计数
iptables-save -t filter -c > /etc/iptables-20220211-filter.rule

# 查看备份文件
cat /etc/sysconfig/iptables
cat /etc/iptables-20220211.rule

这样,就完成了iptables规则的备份。

1.2.3.6.2 iptables save

安装iptables服务之后,也可以通过iptables save命令来实现防火墙规则的保存。

默认iptables save命令是将内核中的规则打印到标准输出,但是可以通过重定向到文件的方式来实现规则的保存。

# 先设置几条规则
iptables -t filter -I INPUT -p icmp -j REJECT
iptables -t filter -I INPUT -p tcp -s 192.168.126.39 -j DROP

# 查看规则
iptables --line -nvxL
iptables-save  # 将内核中的规则打印到标准输出,要备份的话可以通过重定向到文件实现

# 备份规则
iptables-save > /etc/iptables-20220211.rule

# 备份指定表的规则,-c表示输出中显示每条规则当前报文的技计数
iptables-save -t filter -c > /etc/iptables-20220211-filter.rule

# 查看备份文件
cat /etc/iptables-20220211.rule
1.2.3.7 恢复规则

当主机重启后,我们需要从备份的iptables规则中恢复,需要使用iptables-restore命令。

# 模拟重启后iptables规则清空
iptables -t filter -F INPUT

# 查看规则
iptables --line -nvxL
iptables-save

# 恢复规则
iptables-restore < /etc/iptables-20220211.rule

# 查看规则
iptables --line -nvxL
iptables-save

image-20220211153840962

1.2.3.8 小结
1.2.3.8.1 添加规则
  • 添加规则时,规则的顺序很重要

  • 省略-t参数时,默认操作的是fliter

  • 在指定表的指定链尾部添加规则使用-A参数:

    # 命令语法
    iptables -t 表名 -A 链名 匹配条件 -j 动作
    
    # 示例
    iptables -t filter -A INPUT -s 192.168.126.39 -j DROP
    
  • 在指定表的指定链顶部添加规则使用-I参数:

    # 命令语法
    iptables -t 表名 -I 链名 匹配条件 -j 动作
    
    # 示例
    iptables -t filter -I INPUT -s 192.168.126.39 -j ACCEPT
    
  • 在指定表的指定链的指定位置添加一条规则:

    # 命令语法
    iptables -t 表名 -I 链名 规则序号 匹配条件 -j 动作
    
    # 示例
    iptables -t filter -I INPUT 5 -s 192.168.126.39 -j REJECT
    
  • 设置指定表的指定链的默认策略(默认动作),并非添加规则:

    # 命令语法
    iptables -t 表名 -P 链名 动作
    
    # 示例
    iptables -t filter -P FORWARD ACCEPT
    
1.2.3.8.2 删除规则
  • 如果没有保存规则,在删除时必须慎重

  • 按照规则序号删除规则,删除指定表的指定链的指定规则,-D选项表示删除对应链中的规则:

    # 命令语法
    iptables -t 表名 -D 链名 规则序号
    
    # 示例
    iptables -t filter -D INPUT 3
    
  • 按照具体的匹配条件与动作删除规则,删除指定表的指定链的指定规则:

    # 命令语法
    iptables -t 表名 -D 链名 匹配条件 -j 动作
    
    # 示例
    iptables -t filter -D INPUT -s 192.168.126.39 -j DROP
    
  • 删除指定表指定链所有规则时要三思:

    # 命令语法
    iptables -t 表名 -F 链名
    
    # 示例
    iptables -t filter -F INPUT
    
  • 删除所有表中的所有规则时要三思:

    # 命令语法
    iptables -t 表名 -F
    
    # 示例
    iptables -t filter -F
    
1.2.3.8.3 修改规则
  • 如果使用-R选项修改规则中的动作,那么必须指明原规则中的原匹配条件,例如源IP,目标IP等。

  • 如果使用-R选项修改规则中的动作,那么必须指明原规则中的原匹配条件,例如源IP,目标IP等:

    # 命令语法
    iptables -t 表名 -R 链名 规则序号 规则原本的匹配条件 -j 动作
    
    # 示例
    iptables -t filter -R INPUT 3 -s 192.168.126.39 -j ACCEPT
    

    上述示例表示修改filter表中INPUT链的第3条规则,将这条规则的动作修改为ACCEPT, -s 192.168.126.39为这条规则中原本的匹配条件,如果省略此匹配条件,修改后的规则中的源地址可能会变为0.0.0.0/0。

  • 推荐修改方法:

    • 先通过规则编号删除规则
    • 再在原编号位置添加一条规则
  • 修改指定表的指定链的默认策略(默认动作),并非修改规则,可以使用如下命令:

    # 命令语法
    iptables -t 表名 -P 链名 动作
    
    # 示例
    iptables -t filter -P FORWARD ACCEPT
    
1.2.3.8.4 保存规则
  • 保存规则命令如下,表示将iptables规则保存至/etc/sysconfig/iptables文件中:

    service iptables save
    

    如果对应的操作没有保存,那么当重启iptables服务以后,没有保存的防火墙规则会丢失。

  • 或者通过iptables save命令保存规则:

    iptables-save > /etc/sysconfig/iptables
    
1.2.3.8.5 载入规则
  • 可以使用如下命令从指定的文件载入规则,注意:重载规则时,文件中的规则将会覆盖现有规则:

    iptables-restore < /etc/sysconfig/iptables
    

1.3 Iptables基本匹配

1.3.1 Iptables匹配参数

条件参数含义
[!] -p,--protocol protocol指明需要匹配的协议,如icmp、tcp、udp
[!] -s,--source address/mask指定匹配源地址,如果有多个可以用英文逗号隔开
[!] -d,--destination address/mask指定匹配目标地址,如果有多个可以用英文逗号隔开
[!] --source-port,--sport port[:port]指定源端口
[!] --destination-port,--dport port[:port]指定目标端口
[!] -i,--in-interface name接收数据包的接口名称
[!] -o,--out-interface name发送数据包的接口名称
-m,--match match执行需要使用的匹配项,属于扩展匹配
-j,--jump target执行匹配规则后的动作,ACCEPT、DROP、REJECT等
  • !表示取反。

  • -s 192.168.126.39:表示匹配源地址为192.168.126.39

  • ! -s 192.168.126.39:表示匹配源地址不是192.168.126.39

1.3.2 匹配条件:源地址

1.3.2.1 匹配单个源地址

iptables规则匹配源地址,使用的是-s参数,之前的示例中都只是指定单个IP,示例如下:

iptables -t filter -I INPUT -s 192.168.126.39 -j DROP

效果如下:image-20220211171557978

1.3.2.2 匹配多个源地址

其实在指定源地址时,可以一次性指定多个源地址,用逗号隔开即可,示例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -s 192.168.126.39,192.168.126.151 -j DROP

效果如下:image-20220211171830713

注意:逗号的两侧都不能有空格!!!

1.3.2.3 匹配某个网段

除了能够匹配具体的IP地址外,还能指定某个网段,示例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -s 192.168.125.0/24 -j DROP

效果如下:image-20220211172321761

1.3.2.4 对匹配条件取反

上述的示例都是匹配到某一个源地址之后执行响应的动作,也可以通过!取反来对匹配条件取反:

iptables -t filter -F INPUT
iptables -t filter -A INPUT ! -s 192.168.126.39 -j ACCEPT

效果如下:image-20220211174747548

! -s 192.168.126.39这个匹配条件表示对-s 192.168.126.39这个匹配条件取反,-s 192.168.126.39表示报文源地址为192.168.126.39即可满足匹配条件,使用!后则表示,报文源地址为不为192.168.126.39就满足条件。那么上述规则表达的意思就是,只要发往本机的报文的源地址不是192.168.126.39,就接收报文。

!取反的时候,只能指定单个IP,不能提供,指定多个源IP。

但是,此时192.168.126.39ping本机还是会被接受的,原因是,没有任何一条规则指明源IP为192.168.126.39时会执行什么动作,所以192.168.126.39不会匹配到任何一条规则,所以会被执行该链的默认动作,而filter表的INPUT链的默认执行动作是ACCEPT

1.3.3 匹配条件:目标地址

除了可以通过-s参数匹配源地址作为匹配条件,还可以通过-d参数匹配目标地址作为匹配条件。

为了更好的实验,在本机上新增了一块网卡,所以现在本机除了127.0.0.1这个回环地址之外,还有两个IP地址:image-20220211180226909

1.3.3.1 丢弃指定源IP到指定目标IP的报文

我们想要拒绝192.168.126.39到本机192.168.126.150发送报文,但是不拒绝192.168.126.39向本机192.168.126.101发送报文,我们就可以指定目标地址作为匹配条件,示例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -s 192.168.126.39 -d 192.168.126.150 -j DROP

效果如下:image-20220212093947546

此时192.168.126.39发往192.168.126.150的报文会被拒绝:image-20220212094234190

1.3.3.2 拒绝所有IP到指定到目标IP的报文

如果不指定源IP匹配条件,则默认源IP为0.0.0.0/0,也就是会拒绝所有的源IP向指定目标IP发送报文(同理,如果不指定目标IP,则默认目标IP为0.0.0.0/0)。

iptables -t filter -F INPUT
iptables -t filter -I INPUT -d 192.168.126.150 -j DROP

效果如下:image-20220212094917354

1.3.3.3 对匹配条件取反

-s参数一样,-d参数也可以通过!来对匹配结果进行取反示例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT ! -s 192.168.126.39 ! -d 192.168.126.101 -j DROP

效果如下:image-20220212095521995

注意:

  • 不管是-s选项还是-d选项,取反操作与同时指定多个IP的操作不能同时使用。
  • 当一条规则中有多个匹配条件时,这多个匹配条件之间,默认存在"与"的关系,也就是说,当一条规则中存在多个匹配条件时,报文必须同时满足这些条件,才算做被规则匹配。

1.3.4 匹配条件:协议

我们可以使用-p选项来指定需要匹配报文的协议类型。

1.3.4.1 拒绝TCP协议

如果我们要拒绝192.168.126.39发往本机192.168.126.150的所有TCP报文,示例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -s 192.168.126.39 -d 192.168.126.150 -p tcp -j REJECT

效果如下:image-20220212100817591

此时我们从192.168.126.39上ssh到192.168.126.150应该是会被拒绝的,因为sshd服务使用的是TCP协议:image-20220212100926279

但是我们在192.168.126.39上ping192.168.126.150是可以ping通的,因为ping使用的是icmp协议:image-20220212101100219

1.3.4.2 -p选项支持的协议类型
  • CentOS6.x中支持如下协议:
    • tcp
    • udp
    • udplite
    • icmp
    • esp
    • ah
    • sctp
  • CentOS7.x中支持如下协议:
    • tcp
    • udp
    • udplite
    • icmp
    • icmpv6
    • esp
    • ah
    • sctp
    • Mh
  • 当不是要-p选项指定匹配协议的时候,默认会匹配所有协议,与使用-p all的效果相同

1.3.5 匹配条件:网卡接口

当本机有多个网卡的时候,我们还可以通过-i选项去匹配报文是通过哪个网卡流入本机的。

当前本机有两个网卡:image-20220212103831990

1.3.5.1 数据报文流入-i选项

如果我们要拒绝由网卡eth0流入的ping请求报文,则需要如下的iptables规则设置:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -i eth0 -p icmp -j REJECT

效果如下:image-20220212104418938

-i选项是用于匹配报文流入的网卡的,也就是说,从本机发出的报文是不可能会使用到-i选项的,因为这些由本机发出的报文压根不是从网卡流入的,而是要通过网卡发出的,从这个角度考虑,-i选项的使用是有限制的。

iptables全局报文流向图(下图):image-20220211104119343

我们可以知道:-i选项是用来判断报文流入的,那么-i参数只能用于上图中的PREROUTING链INPUT链FORWARD链,这是-i选项的特殊性。因为它只是用于判断报文是从哪个网卡流入的,所以只能在上图数据流入流向的链中与FORWARD链中存在,而上图中的数据发出流向经过的链中,是不可能使用-i选项的,比如上图中的OUTPUT链与POSTROUTING链,他们都不能使用-i选项。

1.3.5.2 数据报文流出-o选项

当主机有多块网卡时,可以使用-o选项,匹配报文将由哪块网卡流出,没错,-o选项与-i选项是相对的,-i选项用于匹配报文从哪个网卡流入,-o选项用于匹配报文将从哪个网卡流出。

-i选项只能用于PREROUTING链INPUT链FORWARD链,那么-o选项只能用于FORWARD链OUTPUT链POSTROUTING链

假设我们要拒绝本机数据报文从eth0网卡流出,那么应该设置如下规则:

iptables -t filter -F INPUT
iptables -t filter -I OUTPUT -o eth0 -j REJECT

效果如下:image-20220212142231615

FORWARD链即可以使用-i控制数据报文流入,也可以使用-o控制数据报文流出。

1.3.6 禁止访问指定网站

iptables -t filter -F
iptables -t filter -I OUTPUT -p tcp -d www.baidu.com --dport 80 -j REJECT

效果如下:image-20220215145638821

此时访问www.baidu.comimage-20220215145721453

-d参数也可以使用域名进行匹配,使用域名iptables会自动解析该域名的IP。

1.3.7 基本匹配条件小结

  • -s匹配报文源地址,可以同时指定多个源地址,每个IP之间用英文逗号隔开,也可以指定一个网段作为源地址

    #示例如下
    iptables -t filter -I INPUT -s 192.168.126.39,192.168.126.151 -j DROP
    iptables -t filter -I INPUT -s 192.168.125.0/24 -j ACCEPT
    iptables -t filter -I INPUT ! -s 192.168.125.0/24 -j ACCEPT
    
  • -d匹配目标地址,可以同时指定多个目标地址,每个IP之间用英文逗号隔开,也可以指定一个网段作为目标地址

    #示例如下
    iptables -t filter -I OUTPUT -d 192.168.126.150,192.168.126.151 -j DROP
    iptables -t filter -I INPUT -d 192.168.125.0/24 -j ACCEPT
    iptables -t filter -I INPUT ! -d 192.168.125.0/24 -j ACCEPT
    
  • -p匹配报文协议类型,可以匹配的协议类型tcp、udp、udplite、icmp、esp、ah、sctp等(centos7中还支持icmpv6、mh)

    #示例如下
    iptables -t filter -I INPUT -p tcp -s 192.168.126.39 -j ACCEPT
    iptables -t filter -I INPUT ! -p udp -s 192.168.126.39 -j ACCEPT
    
  • -i匹配报文从哪个网卡设备流入本机,由于匹配条件只是用于匹配报文流入的网卡,所以在OUTPUT链与POSTROUTING链中不能使用此选项

    #示例如下
    iptables -t filter -I INPUT -p icmp -i eth1 -j DROP
    iptables -t filter -I INPUT -p icmp ! -i eth0 -j DROP
    
  • -o匹配报文从本机哪个网卡设备流出,于匹配条件只是用于匹配报文流出的网卡,所以在INPUT链与PREROUTING链中不能使用此选项

    #示例如下
    iptables -t filter -I OUTPUT -p icmp -o eth0 -j DROP
    iptables -t filter -I OUTPUT -p icmp ! -o eth1 -j DROP
    

1.4 Iptables拓展匹配

基本匹配条件我们可以直接使用,而如果想要使用扩展匹配条件,则需要依赖一些扩展模块,或者说,在使用扩展匹配条件之前,需要指定相应的扩展模块才行。

# 查看iptables支持的扩展模块
rpm -ql iptables|grep ".so"| wc -l

1.4.1 Iptables扩展模块-tcp

1.4.1.1 目标端口匹配

sshd服务默认的端口为22,当我们使用ssh工具远程连接主机时,默认会连接主机的22端口,加入我们要通过一条iptables规则来拒绝192.168.126.39的ssh请求,我们可以通过拒绝192.168.126.39对本机22号端口的数据报文,这个时候就需要通过扩展匹配来对目标端口进行限制:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m tcp --dport 22 -j REJECT

效果如下:image-20220214102408879

此时从192.168.126.39主机上ssh连接本机会直接被拒绝:image-20220214102558542

需要注意的是,--dport前面有两个-,而且使用--dport选项前,必须要先指定匹配哪种协议,即,必须要使用-p选项。

如上,我们使用了扩展匹配条件--dport,指定报文匹配的目标端口,如果外来报文的目标端口是本机的22端口(ssh默认端口),则拒绝该数据报文,而在使用--dport之前,我们使用了-m tcp指定了对应的扩展模块为tcp,也就是说,如果想要使用--dport这个扩展匹配条件,必须依靠某个模块完成,上例中,这个扩展模块就是tcp扩展模块,最终,我们使用的是tcp扩展模块中的--dport扩展匹配条件。

-m tcp表示使用tcp扩展模块,--dport表示tcp扩展模块中的一个扩展匹配条件,可用于匹配报文的目标端口。

注意,-p tcp -m tcp并不冲突,-p用于匹配报文的协议,-m用于指定扩展模块的名称,正好,这个扩展模块也叫tcp。

其实,在上面的例子中,我们也可以省略-m tcp,实例如下:

iptbles -t filter -I INPUT -s 192.168.126.39 -p tcp --dport 22 -j REJECT

效果如下:image-20220214103501595

我们可以看到,省略-m tcp与之前的规则其实是一样的。那是因为,当使用-p选项指定了报文的协议时,如果在没有使用-m指定对应的扩展模块名称的情况下,使用了扩展匹配条件, iptables默认会调用与-p选项对应的协议名称相同的模块。

上例中,我们使用-p选项指定了协议名称,使用扩展匹配条件--dport指定了目标端口,在使用扩展匹配条件的时候,如果没有使用-m指定使用哪个扩展模块,iptables会默认使用-m 协议名,而协议名就是-p选项对应的协议名,上例中,-p对应的值为tcp,所以默认调用的扩展模块就为-m tcp,如果-p对应的值为udp,那么默认调用的扩展模块就为-m udp

所以,上例中,其实隐式的指定了扩展模块,只是没有表现出来罢了。

所以,在使用扩展匹配条件时,一定要注意,如果这个扩展匹配条件所依赖的扩展模块名正好与-p对应的协议名称相同,那么则可省略-m选项,否则则不能省略-m选项,必须使用-m选项指定对应的扩展模块名称。

1.4.1.2 源端口匹配

目标端口就有源端口,代表源端口的扩展匹配条件为--sport

使用--sport可以判断报文是否从指定端口发出,即匹配报文的源端口是否与指定端口一致,--sport表示source-port,即表示源端口之意。

同样的,如果我们要允许报文从192.168.126.3922端口发往本机,则应该设置如下的规则:

iptables -t filter -I INPUT -s 192.168.126.39 -p tcp --sport 22 -j ACCEPT

效果如下:image-20220214135702085

-m tcp也可以省略。

同基本匹配规则一样,扩展匹配规则也可以使用!进行匹配结果取反。

不管是--dport还是--sport,都能够指定一个端口范围进行匹配(但是!取反的时候,只能匹配单个端口),示例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m tcp --sport 22:25 --dport 22:25 -j REJECT

效果如下:image-20220214140330798

也可以写成如下的模样,下图第一条规则表示匹配022之间的所有端口,下图第二条规则表示匹配8065535之间的所有端口:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m tcp --dport :22 -j REJECT
 iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m tcp --dport 80: -j REJECT

效果如下:image-20220214140714051

借助--dport--sport可以指定一个端口,或者一个连续的端口范围,但是无法同时指定多个离散的、不连续的端口,如果想要同时指定多个离散的端口,需要借助另一个扩展模块multiport

1.4.2 Iptables扩展模块-multiport

  • 可以使用multiport模块的--sports扩展条件同时指定多个离散的源端口
  • 可以使用multiport模块的--dports扩展条件同时指定多个离散的目标端口

实例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m multiport --dports 25,3306,8080 -j DROP
iptables -t filter -A INPUT -s 192.168.126.39 -p tcp -m multiport --sports 22,80,443 -j REJECT

效果如下:image-20220214141754756

上图第一跳规则表示禁止192.168.126.39主机上的tcp报文访问本机的25端口、3306端口和8080端口;

上图第二条规则表是拒绝192.168.126.39主机上来自22端口、80端口和443端口到本机的tcp协议报文。

其中-m multiport --dports 25,3306,8080-m multiport --sports 22,80,443表示使用了扩展模块multiport中的--dports--sports扩展匹配规则,同时指定了多个离散的端口,每个端口之间用英文逗号隔开,并且逗号两边都没有空格。

上图中的-m multiport是不能省略的,如果你省略了-m multiport,就相当于在没有指定扩展模块的情况下,使用了扩展匹配条件(--dports--sports),那么上例中,iptables会默认调用-m tcp,但是--dports--sports并不属于tcp扩展模块中的匹配条件,所以就会报错。

其实,使用multiport模块的--sports--dpors时,也可以指定连续的端口范围,并且能够在指定连续的端口范围的同时,指定离散的端口号,示例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m multiport --dports 25,3306,8080:8100 -j REJECT

效果如下:image-20220214142948919

上图的规则表示拒绝来自192.168.126.39发送tcp报文请求本机的25端口、3306端口和80808100的端口,相对于tcp扩展模块的--dport--sport来得更加灵活和方便。

注意:multiport扩展模块只能用于tcp协议或者udp协议,即必须配合-p tcp或者-p udp使用。

1.4.3 Iptables扩展模块-iprange

在不使用任何扩展模块的情况下,使用-s选项或者-d选项即可匹配报文的源地址与目标地址,而且在指定IP地址时,可以同时指定多个IP地址,每个IP用”逗号”隔开,但是,-s选项与-d选项并不能一次性的指定一段连续的IP地址范围,如果我们需要指定一段连续的IP地址范围,可以使用iprange扩展模块。

使用iprange扩展模块可以指定一段连续的IP地址范围,用于匹配报文的源地址或者目标地址。

与不使用扩展模块的-s-d匹配条件对应的,iprange模块有--src-range--dst-range两个扩展匹配条件,分别用于匹配报文的源地址所在范围与目标地址所在范围。

示例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -p tcp -m iprange --src-range 192.168.126.40-192.168.126.69 -j DROP
iptables -t filter -A INPUT -p tcp -m iprange --dst-range 192.168.126.155-192.168.126.180 -j REJECT

效果如下:image-20220214152648382

上图表示如果tcp报文的源IP在192.168.126.40192.168.126.69之间,则丢弃该报文,tcp报文的目标IP在192.168.126.155192.168.126.180之间,则拒绝该报文。

multiport扩展模块的--src-range--dst-range扩展匹配条件的IP段的始末IP使用-进行连接,并且都支持!对匹配结果进行取反。

1.4.4 Iptables扩展模块-string

使用string扩展模块,可以指定要匹配的字符串,如果报文中包含对应的字符串,则符合匹配条件。

比如,如果报文中包含字符串XXOO,我们就拒绝当前报文。

首先我们启动web服务(以Nginx为例),提供两个页面,分别如下:image-20220214155013037

1.4.4.1 在客户端本地做防火墙规则(filter表的INPUT链)

在没有配置任何防火墙规则的时候,192.168.126.39可以正常访问到这两个页面:image-20220214155839778

image-20220214155154819

那么,我们要想达到报文中只要包含XXOO字符,我们就拒绝报文,所以访问web服务的客户端主机192.168.126.39配置如下防火墙规则:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -m string --algo bm --string "XXOO" -j REJECT

效果如下:image-20220214155721229

上图中,-m string表示使用string模块,–algo bm表示使用bm算法去匹配指定的字符串,–string XXOO则表示我们想要匹配的字符串为XXOO

配置完防火墙规则后,由于http://192.168.126.150/index1.html返回的请求报文中包含字符串XXOO,所以无法进入192.168.126.39防火墙的INPUT链,所以无法获取到页面的内容。

1.4.4.2 在web服务器做防火墙规则(filter表的OUTPUT链)

同样的服务,我们在web服务器上做防火墙规则:

iptables -t filter -F
iptables -t filter -I OUTPUT -p tcp -m string --algo kmp --string "XXOO" -j DROP

效果如下:image-20220215144754081

客户端192.168.126.39上清空所有防火墙规则,然后访问:image-20220215145053536

string魁扩展模块的常用选项:

  • --algo:用于指定匹配算法,可选的算法有bmkmp,此选项为必选项,我们不用纠结于选择哪个算法,但是我们必须指定一个。
  • --string:用于指定需要匹配的字符串。

1.4.5 Iptables扩展模块-time

通过time扩展模块,根据时间段区匹配报文,如果报文到达的时间在指定的时间范围以内,则符合匹配条件。

1.4.5.1 根据时间段匹配

假如要实现每天的08:30:0015:15:00决绝所有的icmp请求报文,那么可以设置如下的防火墙规则:


iptables -t filter -F INPUT
iptables -t filter -I INPUT -p icmp -m time --timestart 00:30 --timestop 07:15 -j REJECT

因为iptables的time扩展模块使用的是UTC时间,会比我们本地(中国大陆)快8小时,所以要在规定的时间上减去8小时来进行书写规则。

也可以使用--kerneltz来使用内核时区,但是这个参数使用会有问题,测试使用的时候发现即使不在规定时间内,还是无法ping通主机。不推荐使用

效果如下:image-20220215152001849

在时间范围内,无法ping通本机:image-20220215152035459

时间范围外,成功ping通本机:image-20220215152106082

1.4.5.2 根据周几匹配

使用--weekdays选项可以指定每个星期的具体哪一天,可以同时指定多个,用英文逗号隔开,除了能够数字1-7表示星期几,还能用缩写表示,例如:MonTueWedThuFriSatSun

如果要设置本机工作日(周一到周五)无法访问外网,则可以设置如下的防火墙规则:

iptables -t filter -F
iptables -t filter -I OUTPUT -p tcp -m multiport --dports 80,443 -m time --weekdays 1,2,3,4,5 -j REJECT

效果如下:image-20220215153224386

最终实现的效果如下:image-20220215153332032

1.4.5.3 根据每个月的哪一天匹配

使用--monthdays选项可以指定每个月的具体哪一天,可以同时指定多个,用英文逗号隔开。

假如要设置本机每个月的1号和25号不能访问外网,那么可以设置下面的规则:

iptables -t filter -F
iptables -t filter -I OUTPUT -p tcp -m multiport --dports 80,443 -m time --monthdays 1,25 -j REJECT

效果如下:image-20220215153834616

1.4.5.4 根据日期范围匹配

除了--timestart--timestop--weekdays--monthdays之外,还可以使用--datestart--datestop来根据具体的日期范围进行匹配。实例如下:

iptables -t filter -F
iptables -t filter -I OUTPUT -p tcp -m multiport --dports 80,443 -m time --datestart 2022-02-15 --datestop 2022-02-20 -j REJECT

效果如下:image-20220215154347724

之前已经总结过,当一条iptables规则同时有多个匹配条件时,所有的匹配条件都是关系。

time扩展模块也支持!匹配条件取反。

1.4.5.5 与string扩展模块配合使用示例
  • 将iptables主机当做路由器使用

在工作日(周一到周五)期间,上午8点到12点,下午13:30到18点禁止访问指定的网站:

# 工作日上午
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "qq.com" -m time --weekdays 1,2,3,4,5 --timestart 00:00 --timestop 04:00 -j DROP
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "weixin.qq.com" -m time --weekdays 1,2,3,4,5 --timestart 00:00 --timestop 04:00 -j DROP
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "taobao.com" -m time --weekdays 1,2,3,4,5 --timestart 00:00 --timestop 04:00 -j DROP
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "jd.com" -m time --weekdays 1,2,3,4,5 --timestart 00:00 --timestop 04:00 -j DROP
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "douyin.com" -m time --weekdays 1,2,3,4,5 --timestart 00:00 --timestop 04:00 -j DROP
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "kuaishou.com" -m time --weekdays 1,2,3,4,5 --timestart 00:00 --timestop 04:00 -j DROP

# 工作日下午
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "qq.com" -m time --weekdays 1,2,3,4,5 --timestart 05:30 --timestop 10:00 -j DROP
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "weixin.qq.com" -m time --weekdays 1,2,3,4,5 --timestart 05:30 --timestop 10:00 -j DROP
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "taobao.com" -m time --weekdays 1,2,3,4,5 --timestart 05:30 --timestop 10:00 -j DROP
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "jd.com" -m time --weekdays 1,2,3,4,5 --timestart 05:30 --timestop 10:00 -j DROP
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "douyin.com" -m time --weekdays 1,2,3,4,5 --timestart 05:30 --timestop 10:00 -j DROP
iptables -t filter -I FORWARD -p tcp -m string --algo kmp --string "kuaishou.com" -m time --weekdays 1,2,3,4,5 --timestart 05:30 --timestop 10:00 -j DROP

1.4.6 Iptables扩展模块-icmp

ICMP协议的全称为Internet Control Message Protocol,翻译为互联网控制报文协议,它主要用于探测网络上的主机是否可用,目标是否可达,网络是否通畅,路由是否可用等。

使用ping命令ping某主机时,如果主机可达,对应主机会对我们的ping请求做出回应(此处不考虑禁ping等情况),也就是说,我们发出ping请求,对方回应ping请求,虽然ping请求报文与ping回应报文都属于ICMP类型的报文,但是如果在概念上细分的话,它们所属的类型还是不同的,我们发出的ping请求属于类型8的icmp报文,而对方主机的ping回应报文则属于类型0的icmp报文,根据应用场景的不同,icmp报文被细分为如下各种类型:image-20220221095652328

当我们设置下面的这个规则之后,所有的主机无法ping通本机,但是本机也无法ping通其他主机

iptables -t filter -F
iptables -t filter -I INPUT -p icmp -j DROP

显然这不是最好的结果,我们应该比较希望别的主机无法ping通本机,但是不影响本机ping通其他主机,这时候就需要借助扩展模块icmp了。

iptables -t filter -F INPUT
iptables -t filter -I INPUT -p icmp -m icmp --icmp-type "echo-request" -j REJECT

效果如下:image-20220215161302417

此时192.168.126.39无法ping通本机:image-20220215161401318

但是本机可以ping通192.168.126.39image-20220215161454412

  • -m icmp:指定扩展模块为icmp,其实上例中,我们指定了-p icmp,也可以省略-m icmp
  • --icmp-type:指定ICMP类型
    • echo-request(8请求):icmp请求类型
    • echo-reply(0回应):icmp响应类型

所以iptables -t filter -I INPUT -p icmp -m icmp --icmp-type "echo-request" -j REJECT就是只拒绝了icmp的请求,并不拒绝icmp的响应类型。

1.4.7 Iptables扩展模块-connlimit

connlimit扩展模块可以限制每个客户端IP到服务器的并行连接数量。我们不需要指定某个特定的IP,它默认对每个IP都进行并发限制。

1.4.7.1 connlimit-avove

--connlimit-avove n表示如果单个客户端IP到服务器的并发连接数大于n,则匹配成功。

假如我们要限制客户端请求并发数,当请求并发数大于2的时候我们就拒绝报文请求。

说明:因为之前在防火墙这台主机上安装了Nginx并提供了两个页面,所以我们基于Nginx这个web服务进行测试。

通过一个模拟DDOS的脚本进行访问,脚本内容比较多,点击下载 flood_connect.c

在客户端上下载完成之后,需要编译才能运行:

gcc flood_connect.c -o folld_connect

编译完成后,会在当前路径下生成一个flood_connect的二进制可执行文件。

运行脚本之前,查看一下服务端TCP连接状态:image-20220217104011447

然后开始运行脚本模拟DDOS:

./flood_connect 192.168.126.150

效果如下:image-20220217104110892

再次查看服务端TCP连接状态:image-20220217104200918

然后在服务端设置如下防火墙规则:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -p tcp --dport 80 -m connlimit --connlimit-above 2 -j DROP

效果如下:image-20220217104409641

再次查看服务端TCP连接状态:image-20220217104454598

说明防火墙规则已经生效了。

1.4.7.2 connlimit-upto

--connlimit-upto n表示如果单个客户端IP到服务器的并发连接数小于等于n,则匹配成功。

同样是上面一样的需求,我们通过--connlimit-upto来设置防火墙规则,首先清楚上一步中的防火墙规则并查看服务端TCP连接状态:

iptables -t filter -F INPUT
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

如下图,TCP连接数又上升了:image-20220217104831271

然后设置如下规则:

iptables -t filter -I INPUT -p tcp --dport 22 -j ACCEPT  # 保证ssh连接不被拒绝
iptables -t filter -I INPUT -p tcp --dport 80 -m connlimit --connlimit-upto 2 -j ACCEPT

iptables -P INPUT DROP  # 设置INPUT链默认动作为DROP

然后查看服务端TCP连接状态:image-20220217110826797

注意:

  • 这个匹配条件在CentOS7.x的系统中才出现。
  • 这个选项的含义与! –commlimit-above的含义相同,即链接数量未达到指定的连接数量之意。
  • --connlimit-upto选项不常用。
1.4.7.3 connlimit-mask

--connlimit-above默认表示限制每个IP的链接数量,其实,我们还可以配合--connlimit-mask选项,去限制某类网段的链接数量,示例如下:

iptables -P INPUT ACCEPT  # 将INPUT链默认动作改回ACCEPT
iptables -t filter -F INPUT

此时查看服务端TCP连接状态:image-20220217111621912

然后设置如下规则:

iptables -t filter -I INPUT -p tcp --dport 80 -m connlimit --connlimit-above 2 --connlimit-mask 24 -j DROP

效果如下:image-20220217112339668

上例中,--connlimit-mask 24表示某个C类网段,没错,mask为掩码之意,所以将24转换成点分十进制就表示255.255.255.0,所以,上图示例的规则表示,一个最多包含254个IP的C类网络中,同时最多只能有2个客户端可以请求当前的80端口。

如果将connlimit-mask 24改为connlimit-mask 27那么通过计算后可以得知,这个网段中最多只能有30台机器(30个IP),这30个IP地址最多只能有2个连接同时连接到服务器的80端扣,当然,这样并不能避免某个IP占用所有连接的情况发生,假设,报文来自192.168.126.39这个IP,按照掩码为27进行计算,这个IP属于192.168.126.32/27网段,如果192.168.126.39同时占用了2个连接,那么当192.168.126.51这个IP向服务端发起连接请求时,同样会被拒绝,因为192.168.126.51这个IP按照掩码为27进行计算,也是属于192.168.1.32/27网段,所以他们共享这2个连接名额。但是如果192.168.126.33-192.168.126.62之外的IP连接就不受这个连接名额限制。

  • 在不使用connlimit-mask的情况下,连接数量的限制是针对每个IP而言的
  • 当使用了connlimit-mask选项以后,则可以针对某类IP段内的一定数量的IP进行连接数量的限制,这样就能够灵活许多.

1.4.8 Iptables扩展模块-limit

connlimit模块是对连接数量进行限制的,limit模块是对报文到达速率进行限制的。也就是说如果想要限制单位时间内流入的包的数量,就能用limit模块。

可以以秒为单位进行限制,也可以以分钟、小时、天作为单位进行限制。

  • --limit number/[second|minute|hour|day]:平均匹配速率
  • --limit-burst number:超过限制速率的包,允许超过burst所设定值,默认可超出5个
1.4.8.1 限制数据包流入速率

假如我们要限制外部主机ping本机的时候,本机最多每6秒钟放行一个ping包,那么我们需要进行如下的防火墙规则设置:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -p icmp -m limit --limit 10/miunte -j ACCEPT # 每分钟放行10个,也就是每6秒放行一个
iptables -t filter -A INPUT -p icmp -j REJECT  # 其他的ping包全部拒绝

效果如下:image-20220217142717852

此时另一台主机上ping该主机:image-20220217143205582

结果发现,只有前5个ping包没有受到限制,之后的ping包已经开始受到了规则的限制了。

1.4.8.2 limit-burst

从上图可以看出,除了前5个ping包以外,之后的ping包差不多每6秒才能ping通一次,看来,之后的ping包已经受到了规则的控制,被限制了流入防火墙的速率了,那么,前5个ping包为什么不受规则限制呢?其实,这个现象正好引出另一个话题,出现上图中的情况,是因为另一个选项:–limit-burst

–limit-burst选项可以指定空闲时可放行包的数量,这样说其实并不准确,但是可以先这么理解,在不设置–limit-burst的时候,默认值为5,这个在设置的防火墙规则中也可以看到。image-20220217143510658

所以才会出现上面前5个ping包并没与收到任何速率限制,而之后的包才受到了规则限制。

1.4.8.3 令牌桶算法

如果想要彻底了解limit扩展模块的工作原理,我们需要先了解一下令牌桶算法,因为limit模块使用了令牌桶算法。

首先,假设防火墙是一个关卡,每一个数据包出入防火墙都必须持有一个通关的令牌,而令牌又由防火墙进行生成,并且防火墙每6秒钟生成一个令牌,生成以后放置在一个木桶当中,而木桶只能放下5个令牌,新生成的令牌如果放不进木桶,就会自动销毁。一开始的时候,木桶中已经放满了5个令牌,这时候来了5个数据包需要过关,刚好一个数据包一个令牌,5个数据包刚好全部过关了,后面再来的数据包因为拿不到令牌所以必须要等新的令牌生成被放到木桶中它才可以拿着令牌过关。如果一段时间没有数据包要过关,那么木桶中的令牌又会被放满5个,直到有需要的数据包拿走令牌。这就是令牌桶算法的大致逻辑。

--limit就是指定防火墙生成令牌速率的,而--limit-burst选项就是控制木桶最大存放令牌数量的。

如果想要控制一开始被放行的包的数量,可以在设置防火墙规则的时候通过--limit-burst来设置,示例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -p icmp -m limit --limit 10/miunte --limit-burst 10 -j ACCEPT # 每分钟放行10个,并且前10个包不会被规则限制速率
iptables -t filter -A INPUT -p icmp -j REJECT  # 其他的ping包全部拒绝
1.4.8.4 限制数据包流出速率

那么我们如果想要通过iptables实现路由器的带宽限制,那么我们应该怎么设置防火墙规则呢?

比如我们要限制每秒的带宽不超过300K,那么应该设置如下规则:

# (300K * 1000) / 1500 = 200个包
iptables  -t filter -F OUTPUT
iptables -t filter -I OUTPUT -p tcp -m limit --limit 200/second -j ACCEPT
iptables -t filter -A OUTPUT -p tcp -j DROP

1.4.9 Iptables扩展模块-tcp-flags

上面有关于tcp扩展模块中--sport--dport选项的说明,但是并没有对--tcp-flag选项进行说明。

见名知义,--tcp-flags指的就是tcp头中的标志位,看来,在使用iptables时,我们可以通过此扩展匹配条件,去匹配tcp报文的头部的标识位,然后根据标识位的实际情况实现访问控制的功能。

TCP头部的标志位如下图所示:image-20220217154500535

在使用iptables时,使用tcp扩展模块的tcp-flags选项,即可对上图中的标志位进行匹配,判断指定的标志位的值是否为1,而tcp header的结构不是重点,在tcp协议建立连接的过程中,需要先进行三次握手,而三次握手就要依靠tcp头中的标志位进行。

1.4.9.1 TCP请求三次握手
  1. 第一次握手:客户端向服务端发起TCP连接,在TCPflag标志位SYNRSTACKFIN中,只有SYN被设为1,其他标志位为0
  2. 第二次握手:服务端向客户端返回ACK,在TCPflag标志位SYNRSTACKFIN中,ACKSYN被设为1,其他位为0
  3. 第三次握手:客户端向服务端返回ACK,在TCPflag标志位SYNRSTACKFIN中,只有ACK被设为1,其他标志位为0

我们可以通过--tcp-flags选项指明要匹配哪些标志位,然后指定在指明的标志位中,哪些必须为1,剩余的必须为0。

所以:

  • 当服务器接收新请求时,SYN标志位必须为1,其他标志位为0
  • 服务端响应这个连接时,ACKSYN标志位必须为1,其他标志位为0(这样可以避免木马程序通过端口主动向外发送新连接)。
1.4.9.2 拒绝客户端建立连接的请求

要匹配ssh连接第一次握手的报文,可以使用如下的命令:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -p tcp --dport 22 -m tcp --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN -j REJECT

效果如下:image-20220217160844208

设置这个规则之后,新的ssh连接将无法成功建立:image-20220217160938738

-m tcp –dport 22的含义在前文中已经总结过,表示使用tcp扩展模块,指定目标端口为22号端口(ssh默认端口),–tcp-flags就是扩展匹配条件,用于匹配报文tcp头部的标志位,SYN,ACK,FIN,RST,URG,PSH SYN这串字符就是用于配置我们要匹配的标志位,我们可以把这串字符拆成两部分去理解,第一部分为SYN,ACK,FIN,RST,URG,PSH,第二部分为SYN

  • 第一部分表示:我们需要匹配报文tcp头中的哪些标志位,那么上例的配置表示,我们需要匹配报文tcp头中的6个标志位,这6个标志位分别为为SYNACKFINRSTURGPSH,我们可以把这一部分理解成需要匹配的标志位列表。
  • 第二部分表示:第一部分的标志位列表中,哪些标志位必须为1,上例中,第二部分为SYN,则表示,第一部分需要匹配的标志位列表中,SYN标志位的值必须为1,其他标志位必须为0。
1.4.9.3 拒绝服务端响应客户端建立连接的请求

那么如果我们要拒绝本机响应客户端建立连接的请求,也就是要匹配TCP三次握手中的第二次握手的报文,那么应该设置如下的规则:

iptables -t filter -F
iptables -t filter -I OUTPUT -p tcp --sport 22 -m tcp --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN,ACK -j REJECT

效果如下:image-20220217161853758

此时客户端发起ssh请求的第一次握手能够到达服务端,但是服务端对此请求的响应会被拒绝,所以客户端无法接收到服务端的响应报文,ssh连接会一直等到超时,也无法建立:image-20220217163153151

如上图,客户端一直接收不到服务端响应。

上面的规则书写方法可以简写成下面的格式:

iptables -t filter -F
iptables -t filter -I OUTPUT -p tcp --sport 22 -m tcp --tcp-flags ALL SYN,ACK -j REJECT

没错,我们可以用ALL表示SYN,ACK,FIN,RST,URG,PSH

其实tcp扩展模块还专门提供了一个选项--syn,可以匹配到TCP连接三次握手的第一次报文。使用--syn就相当于使用了-m tcp --tcp-flags ALL SYN或者--tcp-flags SYN,RST,ACK,FIN SYN

示例如下:

iptables -t filter -I INPUT -p tcp --dport 22 --syn -j REJECT
1.4.9.4 拒绝TCP第三次握手的报文

前面已经拒绝了ssh服务第一次握手的报文和第二次握手的报文,都会导致ssh连接无法建立,那么如果拒绝第三次握手的报文,ssh连接应该也无法成功建立:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -p tcp --dport 22 -m tcp --tcp-flags ALL ACK -j REJECT

效果如下:image-20220217163346692

此时尝试建立ssh连接,服务端无法接收到第三次握手的报文,客户端会一直等待连接成功建立直到超时,然后连接建立失败:image-20220217163153151

1.4.10 Iptables扩展模块-udp

udp扩展模块中能用的匹配条件比较少,只有两个,就是--sport--dport,即匹配报文的源端口与目标端口。

只不过udp扩展模块的--sport--dport是用于匹配UDP协议报文的源端口与目标端口,比如,放行samba服务的137与138这两个UDP端口,示例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -p udp -m udp --dport 137 -j ACCEPT
iptables -t filter -I INPUT -p udp -m udp --dport 138 -j ACCEPT

使用扩展模块的时候,如果扩展模块名称和-p指定的协议名称一样,则可以省略-m指定扩展模块名称不写,上面的写法就可以写为如下这样:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -p udp --dport 137 -j ACCEPT
iptables -t filter -I INPUT -p udp --dport 138 -j ACCEPT

--dport--sport使用连续的端口时,上述的规则还可以简化为如下这样:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -p udp --dport 137:138 -j ACCEPT

但是如果要指定多个离散的不连续的端口,那么就需要配合multiport扩展模块了。

1.4.11 扩展匹配模块小结

1.4.11.1 tcp扩展模块
  • -p tcp -m tcp –sport 用于匹配tcp协议报文的源端口,可以使用冒号指定一个连续的端口范围
  • -p tcp -m tcp –dport用于匹配tcp协议报文的目标端口,可以使用冒号指定一个连续的端口范围
#示例如下
iptables -t filter -I OUTPUT -d 192.168.126.39 -p tcp -m tcp --sport 22 -j REJECT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m tcp --dport 22:25 -j REJECT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m tcp --dport :22 -j REJECT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m tcp --dport 80: -j REJECT
iptables -t filter -I OUTPUT -d 192.168.126.39 -p tcp -m tcp ! --sport 22 -j ACCEPT
1.4.11.2 multiport扩展模块
  • -p tcp -m multiport –sports用于匹配报文的源端口,可以指定离散的多个端口号,端口之间用英文逗号隔开
  • -p udp -m multiport –dports用于匹配报文的目标端口,可以指定离散的多个端口号,端口之间用英文逗号隔开
#示例如下
iptables -t filter -I OUTPUT -d 192.168.126.39 -p udp -m multiport --sports 137,138 -j REJECT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m multiport --dports 22,80 -j REJECT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m multiport ! --dports 22,80 -j REJECT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m multiport --dports 80:88 -j REJECT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m multiport --dports 22,80:88 -j REJECT
1.4.11.3 iprange扩展模块
  • --src-range:指定连续的源地址范围
  • dst-range:指定连续的目标地址范围
# 示例如下
iptables -t filter -I INPUT -m iprange --src-range 192.168.126.127-192.168.126.146 -j DROP
iptables -t filter -I OUTPUT -m iprange --dst-range 192.168.126.127-192.168.126.146 -j DROP
iptables -t filter -I INPUT -m iprange ! --src-range 192.168.126.127-192.168.126.146 -j DROP
1.4.11.4 string扩展模块
  • --algo:指定对应的匹配算法,可用算法为bm、kmp,此选项为必需选项。
  • string:指定需要匹配的字符串
# 示例如下
iptables -t filter -I INPUT -p tcp --sport 80 -m string --algo bm --string "OOXX" -j REJECT
iptables -t filter -I INPUT -p tcp --sport 443 -m string --algo bm --string "OOXX" -j REJECT
1.4.11.5 time扩展模块
  • --timestart:用于指定时间范围的开始时间,不可取反
  • --timestop:用于指定时间范围的结束时间,不可取反
  • --weekdays:用于指定星期几,可取反
  • --monthdays:用于指定每个月的几号,可取反
  • --datestart:用于指定日期范围的开始日期,不可取反
  • --datestop:用于指定日期范围的结束时间,不可取反
# 示例如下
iptables -t filter -I OUTPUT -p tcp --dport 80 -m time --timestart 09:00:00 --timestop 19:00:00 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 443 -m time --timestart 09:00:00 --timestop 19:00:00 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --weekdays 6,7 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --monthdays 22,23 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 80  -m time ! --monthdays 22,23 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --timestart 09:00:00 --timestop 18:00:00 --weekdays 6,7 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --weekdays 5 --monthdays 22,23,24,25,26,27,28 -j REJECT
iptables -t filter -I OUTPUT -p tcp --dport 80  -m time --datestart 2017-12-24 --datestop 2017-12-27 -j REJECT
1.4.11.6 connlimit扩展模块
  • --connlimit-above:单独使用此选项时,表示限制每个IP的链接数量。
  • --connlimit-mask:此选项不能单独使用,在使用--connlimit-above选项时,配合此选项,则可以针对某类IP段内的一定数量的IP进行连接数量的限制,如果不明白可以参考上文的详细解释。
# 示例如下
iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 2 -j REJECT
iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 20 --connlimit-mask 24 -j REJECT
iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 10 --connlimit-mask 27 -j REJECT
1.4.11.7 limit扩展模块
  • --limit-burst:类比令牌桶算法,此选项用于指定令牌桶中令牌的最大数量,上文中已经详细的描述了令牌桶的概念,方便回顾。
  • --limit:类比令牌桶算法,此选项用于指定令牌桶中生成新令牌的频率,可用时间单位有second、minute 、hour、day。
# 实例如下
iptables -t filter -I INPUT -p icmp -m limit --limit 10/miunte -j ACCEPT
iptables -t filter -A OUTPUT -p tcp -j DROP


iptables -t filter -I INPUT -p icmp -m limit --limit 10/miunte --limit-burst 10 -j ACCEPT
iptables -t filter -A OUTPUT -p tcp -j DROP
1.4.11.8 tcp-flag扩展模块
  • --tcp-flags:用于匹配报文的tcp头的标志位
# 示例如下
iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN -j REJECT
iptables -t filter -I OUTPUT -p tcp -m tcp --sport 22 --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN,ACK -j REJECT
iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --tcp-flags ALL SYN -j REJECT
iptables -t filter -I OUTPUT -p tcp -m tcp --sport 22 --tcp-flags ALL SYN,ACK -j REJECT
  • --sync:用于匹配tcp新建连接的请求报文,相当于使用tcp-flags SYN,RST,ACK,FIN SYN
# 示例如下
iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --syn -j REJECT

1.5 Iptables连接追踪-state

当我们通过http的url访问某个网站的网页时,客户端向服务端的80端口发起请求,服务端再通过80端口响应我们的请求,于是,作为客户端,我们似乎应该理所应当的放行80端口,以便服务端回应我们的报文可以进入客户端主机,于是,我们在客户端放行了80端口,同理,当我们通过ssh工具远程连接到某台服务器时,客户端向服务端的22号端口发起请求,服务端再通过22号端口响应我们的请求,于是我们理所应当的放行了所有22号端口,以便远程主机的响应请求能够通过防火墙,但是,作为客户端,如果我们并没有主动向80端口发起请求,也没有主动向22号端口发起请求,那么其他主机通过80端口或者22号端口向我们发送数据时,我们可以接收到吗?应该是可以的,因为我们为了收到http与ssh的响应报文,已经放行了80端口与22号端口,所以,不管是响应我们的报文,还是主动发送给我们的报文,应该都是可以通过这两个端口的,那么仔细想想,这样是不是不太安全呢?如果某些与你敌对的人,利用这些端口主动连接到你的主机,你肯定会不爽的吧,一般都是我们主动请求80端口,80端口回应我们,但是一般不会出现80端口主动请求我们的情况。

在主机数量比较少的时候,我们可以通过类似白名单的方式,对在白名单内的主机和服务放行对应的端口,但是一旦主机数量很多的时候,这显然不是理想的选择。

那么,如果通过--tcp-flags扩展模块去匹配tcp报文的标志位,把外来的第一次请求都拒绝掉,针对基于TCP协议的请求确实可以通过--tcp-flags扩展模块来进行管理,但是如果是UDP或者ICMP协议和其他协议呢?

好像上面的各种方法都不尽理想,那么造成上述问题的根源是什么呢?我们为了让提供服务方能够正常的响应我们的请求,于是在主机上开放了对应的端口,开放这些端口的同时,也出现了问题,别人利用这些开放的端口,主动的攻击我们,他们发送过来的报文并不是为了响应我们,而是为了主动攻击我们。那么问题就是:怎样判断这些报文是为了回应我们之前发出的报文,还是主动向我们发送的报文。

其实上面的问题都可以通过防火墙的state扩展模块来解决。

1.5.1 什么是连接追踪

从字面上理解state是状态的意思,但是有一个高大上的次去解释它,state模块可以让iptables实现连接追踪机制。

  • 连接追踪,顾名思义,就是跟踪(并记录)连接的状态。
  • 连接追踪所做的事情就是发现并跟踪这些连接的状态;这个追踪的状态和TCP协议没有关系。
  • state模块由内核的netfilterIP层实现,可IP层是无连接、无追踪的。那么怎么知道这个IP是否存在?
  • netfilter当用户发送请求的时,会将用户的请求信息存储在内存中开辟的空间中,对应在/proc/net/nf_conntrack
    • 该文件会记录源IP目标IP协议时间状态等信息
    • 当用户再次发起请求,就可以通过文件获取该用户是否来过,以此来实现连接追踪机制
    • 该文件存储的条目数受/proc/sys/net/nf_conntrack_max所设置的大小限制。

1.5.2 连接追踪支持的状态

对于state模块的连接而言,连接其中的报文可以分为5种状态,报文状态可以为NEWESTABLISHEDRELATEDINVALIDUNTRACKED

注意:这里所说的报文状态都是相对于state模块而言的。

  • NEW:连接中的第一个包,在proc/net/nf_conntrack中没有此连接的条目信息,状态就是NEW,我们可以理解为新连接的第一个包的状态为NEW。

  • ESTABLISHED:NEW状态之后,再次建立连接,由于此前的连接还未失效,所以后面的包的状态理解为ESTABLISHED,表示连接已建立。

  • RELATED:相关的连接。比如ftp服务有两个连接,命令连接和数据连接;命令连接有来有往是一个独立的循环,数据连接有来有往也是一个独立的循环,但是两者之间存在着一定的关系,命令连接负责命令传输,数据连接负责数据传输,但是传输什么数据由命令连接中的命令来确定,如果没有对应的命令连接就不会有数据连接,所以我们将这种称为相关联的连接

    说明:如果想要对ftp进行连接追踪,需要单独加载对应的内核模块nf_conntrack_ftp,如果想要自动加载,可以配置/etc/sysconfig/iptables-config文件

  • INVALID:如果一个包无法被识别,或者这个包没有任何状态,那么这个包就出于INVALID状态,说明这个包是无效连接,我们可以主动屏蔽状态为INVALID的报文。

  • UNTRACKED:报文状态为UNTRACKED时表示报文未被追踪,当报文状态为UNTRACKED时通常表示无法找到相关的连接。

关于上述5种状态,可以参考下面的文章:

www.iptables.info/en/connecti…

1.5.3 连接追踪应用场景

  • 防止外部服务主动访问本机
  • 防止本机木马病毒主动访问外部

1.5.4 连接追踪配置场景

1.5.4.1 防止外部服务主动访问

开始的问题的根源就是:怎样判断报文是否是为了回应之前发出的报文。从而可以达到拒绝外部服务主动对本机发起请求。

使用state扩展模块解决,我们只需要放行状态为ESTABLISHED的报文即可,因为如果报文状态为ESTABLISHED,那么这个报文肯定是之前发出去报文的回应,如果还不放心,那么可以将状态为RELATED的报文也一起放行。这样就表示只有回应我们的报文能够通过防火墙,如果是别人主动发送过来的新的报文,则无法通过防火墙,示例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -t filter -A INPUT -j REJECT

效果如下:image-20220221113246902

此时我们可以在本机上ssh连接到192.168.126.39,但是192.168.126.39无法主动连接到本机:image-20220221113354833

image-20220221113427916

如果只是拒绝外部主动访问指定端口,可以结合--dport选项使用,示例如下:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -p tcp --dport 22 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -t filter -I INPUT -p tcp -m multiport --dports 80,443 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -t filter -A INPUT -j REJECT

可以根据自己的实际需求,结合不同的模块进行iptables防火墙规则书写。

1.5.4.2 防止木马病毒主动访问外部

正常情况下,服务器的80和443端口是对外提供服务的,不会主动连接其他主机或者服务,如果出现了这两个端口主动访问外部服务或者主机,那就说明出现了异常行为,或者可以理解为中了某些木马病毒。

此时我们就可以借助state扩展模块,防止本机主动发送请求访问外部服务,我们端口出去的报文必须是ESTABLISHED状态的,而不能是NEW状态的,示例如下:

iptables -t filter -F OUTPUT
iptables -t filter -I OUTPUT -p tcp -m multiport --sport 80,443 -m state --state ESTABLISHED -j ACCEPT
iptables -t filter -A OUTPUT j DROP
1.5.4.3 其他配置
# 允许外部主机访问本机22端口和80端口
iptables -t filter -I INPUT -p tcp -m multiport --dports 22,80 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -t filter -A INPUT -p tcp -m multiport --dports 22,80 -j DROP

# 允许本机发送响应ssh和80端口请求
iptables -t filter -I OUTPUT -p tcp -m multiport --sports 22,80 -m state --state ESTABLISHED -j ACCEPT
iptables -t filter -A OUTPUT -p tcp -m multiport --sports 22,80 -j DROP

1.6 Iptables的黑白名单机制

当数据报文在经过iptables的链时,会匹配链中的规则,匹配到规则时会执行对应的动作,如果链中的规则都无法匹配到当前报文,则使用链的默认策略(默认动作),链的默认策略通常设置为ACCEPT或者DROP

当链的默认策略设置为ACCEPT时,如果对应的链中没有配置任何规则,就表示接受所有的报文,如果对应的链中存在规则,但是这些规则没有匹配到报文,报文还是会被接受。

同理,当链的默认策略设置为DROP时,如果对应的链中没有配置任何规则,就表示拒绝所有报文,如果对应的链中存在规则,但是这些规则没有匹配到报文,报文还是会被拒绝。

1.6.1 黑名单机制

当链的默认策略设置为ACCEPT时,按照道理来说,我们在链中配置规则时,对应的动作应该设置为DROP或者REJECT,因为默认策略已经为ACCEPT了,如果我们在设置规则时,对应动作仍然为ACCEPT,那么所有报文都会被放行了,因为不管报文是否被规则匹配到都会被ACCEPT,所以就失去了访问控制的意义。

所以,当链的默认策略为ACCEPT时,链中的规则对应的动作应该为DROP或者REJECT,表示只有匹配到规则的报文才会被拒绝,没有被规则匹配到的报文都会被默认接受,这就是黑名单机制。

1.6.2 白名单机制

同理,当链的默认策略为DROP时,链中的规则对应的动作应该为ACCEPT,表示只有匹配到规则的报文才会被放行,没有被规则匹配到的报文都会被默认拒绝,这就是白名单机制。

1.6.3 说明

  • 白名单机制,链的默认策略是DROP,防火墙规则的动作一般是ACCEEPT,所有匹配到的数据报文都会被拒绝。

  • 黑名单机制,链的默认策略是ACCEPT,防火墙规则的动作一般是DROP或者REJECT,所有未匹配到的数据报文都会被接受。

  • 白名单机制显得会比较安全,而黑名单机制则更加灵活一些。

  • 白名单默认策略为DROP所以一旦使用了清空规则的命令,那么所有的请求都会被拒绝,操作时务必要特别小心。

默认策略设置为DROP的缺点就是,在对应的链中没有设置任何规则时,这样使用默认策略为DROP是非常不明智的,因为管理员也会把自己拒之门外,即使对应的链中存在放行规则,当我们不小心使用iptables -F清空规则时,放行规则被删除,则所有数据包都无法进入,这个时候就相当于给管理员挖了个坑,所以,我们如果想要使用白名单的机制,最好将链的默认策略保持为ACCEPT,然后将拒绝所有请求这条规则放在链的尾部,将放行规则放在前面,这样做,既能实现白名单机制,又能保证在规则被清空时,管理员还有机会连接到主机。

1.7 Iptables自定义链

1.7.1 为什么要使用自定义链?

大部分场景下,iptables默认链已经能够满足我们的需求了,但是在默认链中的规则非常多的时候,不方便我们进行管理。

比如:INPUT链中存放了200条规则,这200条规则有针对httpd服务的,有针对sshd服务的,有针对私网IP的,有针对公网IP的,当我们要修改针对httpd服务的相关规则,我们就必须从头到尾查看一遍规则,然后找出相关的规则再进行修改,这显然比较耗费时间和精力,而且还很容易出错。

iptables也考虑到了这一问题,所以iptables支持自定义链,我们可以根据不同的业务或者服务,自定义其自己的链,这样一个链对应一个业务或者服务,后期维护防火墙规则也显得更加方便。

假设,我们自定义一条链,链名叫IN_WEB,我们可以将所有针对80端口的入站规则都写入到这条自定义链中,当以后想要修改针对web服务的入站规则时,就直接修改IN_WEB链中的规则就好了,即使默认链中有再多的规则,我们也不会害怕了,因为我们知道,所有针对80端口的入站规则都存放在IN_WEB链中,同理,我们可以将针对sshd的出站规则放入到OUT_SSH自定义链中,将针对Nginx的入站规则放入到IN_NGINX自定义链中,这样,我们就能想改哪里改哪里,再也不同担心找不到规则在哪里了。

但是,自定义链并不能直接使用,而是需要被默认链引用之后才能够使用。

1.7.2 自定义链的基本应用

1.7.2.1 创建自定义链
iptables -F  # 清空防火墙规则

iptables -t filter -N IN_WEB  # 在filter表中创建一个自定义链IN_WEB

创建自定义链:image-20220221145304108

-t filter表示操作的是filter表,如果不写-t filter,默认也是操作filter表。

-N IN_WEB表示新建一个叫IN_WEB的自定义链。

0 references表示该自定义链未被任何默认链引用,所以这时候这条自定义链时无法直接使用的。

1.7.2.2 自定义链添加规则
iptables -t filter -I IN_WEB -p tcp -s 192.168.126.39 -m tcp --dport 80 -j REJECT

对自定义链的操作与对默认链的操作并没有什么不同,一切按照操作默认链的方法操作自定义链即可。

效果如下:image-20220221145934165

此时从192.168.126.39测试能否正常访问本机80端口:image-20220221150048872

由上图可以看出,自定义链IN_WEB的防火墙规则并没有生效。

1.7.2.3 引用自定义链

因为IN_WEB链是针对入站的规则而创建的,那么这些规则应该在去匹配入站规则,所以应该在INPUT链中引用它。

iptables -t filter -I INPUT -p tcp --dport 80 -j IN_WEB

效果如下:image-20220221150429950

-j IN_WEB表示:访问80端口的tcp报文将由自定义链”IN_WEB”中的规则进行处理,没错,在之前的示例中,我们使用-j选项指定动作,而此处,我们将动作替换为了自定义链,当-j对应的值为一个自定义链时,就表示被当前规则匹配到的报文将交由对应的自定义链处理,具体怎样处理,取决于自定义链中的规则,当IN_WEB自定义链被INPUT链引用以后,可以发现,IN_WEB链的引用计数已经变为1,表示这条自定义链已经被引用了1次,自定义链还可以引用其他的自定义链,感兴趣的话,可以自己动手试试。

此时再次从192.168.126.39测试能否正常访问本机80端口:image-20220221150717794

1.7.3 重命名自定义链

如果我们需要修改自定义链的名称,那么可以按如下方法进行修改:

iptables -E IN_WEB WEB  # 将自定义链IN_WEB重命名为WEB

使用-E选项可以修改自定义链名,引用自定义链处的名称会自动发生改变。

image-20220221151026075

1.7.4 自定义链执行顺序

  1. 数据报文进入默认链中,进行规则匹配
  2. 如果数据报文符合引用自定义链的规则,则数据报文进入自定义链
  3. 匹配到自定义链的规则,则执行指定的动作
  4. 如果自定义链中所有规则都没有匹配到,那么回到默认链中引用了该自定义链的下一条规则继续进行匹配
  5. 如果默认链中所有规则都没有匹配到,那么执行该默认链的默认策略。

1.7.5 删除自定义链

如果要删除自定义链,使用-X选项就可以删除自定义链,但是在删除自定义链之前,必须要满足两个条件:

  • 自定义链没有被任何默认链引用,即自定义链的引用计数为0。
  • 自定义链中没有任何规则,即自定义链为空。
# 删除自定义链
iptables -X WEB

效果如下:image-20220221151312314

Too many links,是因为WEB链已经被默认链所引用,不满足自定义链没有被任何默认链引用的条件,所以我们要先删除引用:

# 删除自定义链的引用
iptables --line -nvL
iptables -D INPUT 1

image-20220221151550881

此时,WEB这个自定义链的引用计数为0了,再次删除该自定义链:

iptables -X WEB

image-20220221151646820

Directory not empty,是因为WEB链中存在规则,不满足上自定义链中没有任何防火墙规则的条件,所以,我们需要清空对应的自定义链:

iptables -t filter -F WEB  # 清空自定义链
iptables -t filter -X WEB  # 删除一个引用计数为0,没有任何防火墙规则的自定义链

自定义链删除成功:image-20220221152021428

1.8 Iptables作为网络防火墙

防火墙在逻辑上讲,可以分为主机防火墙和网络防火墙:

  • 主机防火墙:针对单个主机进行防护
  • 网络防火墙:往往处于网络入口或边缘,针对于网络入口进行防护,服务于防火墙背后的本地局域网。

上述所有关于iptables的规则都是出于主机防火墙的角度进行的,那么如果用iptables作为网络防火墙应该要怎么实现呢?

image-20220221153716220

上图中,橘黄色的主机为iptables所在的主机,此时该主机充当网络防火墙的角色,浅蓝色圆形表示网络防火墙所防护的网络区域,圆形内的蓝色矩形表示网络内的主机。

当外部网络中的主机与网络内部主机通讯时,不管是由外部主机发往内部主机的报文,还是由内部主机发往外部主机的报文,都需要经过iptables所在的主机,由iptables所在的主机进行过滤并转发,所以,防火墙主机的主要工作就是过滤并转发,iptables都是作为主机防火墙的角色出现的时候,所以我们举例时,只用到了上图中的INPUT链与OUTPUT链,因为拥有过滤功能的链只有3条,INPUTINPUTFORWARD,当报文发往本机时,如果想要过滤,只能在INPUT链与OUTPUT链中实现,而此时,iptables的角色发生了转变,我们想要将iptables所在的主机打造成网络防火墙,而刚才已经说过,网络防火墙的职责就是过滤并转发,要想过滤,只能在INPUT、OUTPUT、FORWARD三条链中实现,要想转发,报文则只会经过FORWARD链(发往本机的报文才会经过INPUT链),所以,综上所述,iptables的角色变为网络防火墙时,规则只能定义在FORWARD链中。

1.8.1 什么是NAT?

网络地址转换(NAT),对(数据包)网络地址(IP + PORT)进行转换。

例如,192.168.126.39能够与外网正常通信,但是172.16.1.39是内网IP,无法与外界通信,因此172.16.1.39需要将自己的源IP转换成192.168.126.39然后再发送出去;收到应答数据包时,再进行相反的转换。这就是NAT的基本过程。

关于更官方的说明可以查看百度百科-NAT

1.8.2 NAT的几种模式

  • SNAT:源地址转换
  • DNAT:目标地址转换
  • PNAT:端口转换

1.8.3 NAT环境搭建

角色外网IP内网IP网关说明
路由器192.168.126.5172.16.1.5192.168.126.2能够访问外网,也在内网之中
客户端/172.16.1.39172.16.1.5无法直接访问外网,只有内网IP
客户端/172.16.1.40172.16.1.5无法直接访问外网,只有内网IP
  • 客户端网关指向Iptables服务器

    # 客户端服务器上操作
    cat >> /etc/sysconfig/network-scripts/ifcfg-eth1 << EOF
    GATEWAY=172.16.1.5
    DNS=223.5.5.5
    EOF
    
    ifdown eth1 && ifup eth1
    ifdown eth0
    
  • 开启内核转发

    # 192.168.126.5上操作
    cat >> /etc/sysctl.conf << EOF
    net.ipv4.ip_forward = 1
    EOF
    
    # 生效
    sysctl -p
    

此时,客户端服务器无法正常访问外网:image-20220222112412279

image-20220222112526766

1.8.4 SNAT场景配置

nat表的POSTROUTING链上实现SNAT,配置如下规则:

iptables -t nat -F POSTROUTING
iptables -t nat -I POSTROUTING -s 172.16.1.0/24 -j SNAT --to 192.168.126.5

效果如下:image-20220222113128949

此时,客户端能够正常访问外网:image-20220222113305950

image-20220222113538947

1.8.5 DNAT场景配置

外部客户端访问iptables主机的80端口,通过DNAT将请求调度到内网中某个服务的80端口。

首先在内网服务器某一台主机上(172.16.1.39)安装httpd对外提供web服务:

yum install -y httpd

echo "Hello" > /var/www/html/index.html

此时外部服务器上应该无法访问到该web服务:image-20220222151210240

我们需要在iptables主机上的nat表的PREROUTING链上配置DNAT,配置规则如下:

iptables -t nat -I PREROUTING -p tcp -d 192.168.126.5 --dport 80 -j DNAT --to 172.16.1.39:80

效果如下:image-20220222151312450

此时外部服务器访问iptables服务器的80端口应该可以被防火墙调度到内网172.16.1.39的80端口:image-20220222151439389

ssh端口转发:

iptables -t nat -A PREROUTING -d 192.168.126.5 -p tcp -m tcp --dport 2222 -j DNAT --to 172.16.1.40:22

此时就可以通过ssh -p 2222 192.168.126.5登陆到内网的172.16.1.40主机上:image-20220222152650785

1.9 Iptables动作

我们知道iptables的链有默认的动作,DROP或者ACCEPT,然后在编写iptables防火墙规则的时候,每个规则也会有对应的动作,在这之前我们使用最多的动作就是DROPACCEPTREJECT

其实和模块一样,动作也分为基础动作扩展动作。其中DROPACCEPT就属于基础动作,而REJECT为扩展动作。

在使用扩展模块的时候我们需要先指定使用哪个扩展模块,才能使用扩展模块的选项进行匹配,但是使用扩展动作不需要指定特定的模块,而是可以直接使用。

1.9.1 基础动作

1.9.1.1 DROP
# 修改链的默认动作
iptables -P INPUT DROP

# 丢弃所有的ping请求数据包,响应ping请求的数据包不会丢弃
iptables -t filter -I INPUT -p icmp -m icmp --icmp-type "echo-request" -j DROP
1.9.2 ACCEPT
# 修改链的默认动作
iptables -P INPUT ACCEPT

# 丢弃所有的ping请求数据包,响应ping请求的数据包不会丢弃
iptables -t filter -I INPUT -p icmp -m icmp  -j ACCEPT

1.9.2 扩展动作

1.9.2.1 REJECT

REJECT常用的选项为--reject-with,使用--reject-with可以设置提示信息,当对方被拒绝时,会提示对方为什么被拒绝。

--reject-with的可用值如下:

  • icmp-net-unreachable

  • icmp-host-unreachable

  • icmp-port-unreachable,

  • icmp-proto-unreachable

  • icmp-net-prohibited

  • icmp-host-pro-hibited

  • icmp-admin-prohibited

当不设置任何值时,默认值为icmp-port-unreachable

当我们拒绝192.168.126.39ping本机,REJECT默认动作为icmp-port-unreachable

iptables -t filter -F INPUT
iptables -t filter -I INPUT -p icmp -s 192.168.126.39 -j REJECT

效果如下:image-20220222154521778

此时从192.168.126.39ping该主机:image-20220222154613071

修改防火墙规则,指定REJECT的提示信息:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -s 192.168.126.39 -p icmp -j REJECT --reject-with icmp-host-unreachable

效果如下:image-20220222154821327

此时从192.168.126.39ping该主机:image-20220222154906241

1.9.2.2 LOG

使用LOG动作,可以将符合条件的报文的相关信息记录到日志中,但当前报文具体是被接受,还是被拒绝,都由后面的规则控制,换句话说,LOG动作只负责记录匹配到的报文的相关信息,不负责对报文的其他处理,如果想要对报文进行进一步的处理,可以在之后设置具体规则,进行进一步的处理。

假设我们要记录所有ssh请求,那么可以设置如下的规则:

iptables -F
iptables -I INPUT -p tcp -m tcp --dport 22 -j LOG

效果如下:image-20220222155307836

此时查看/var/log/messagesimage-20220222155504809

默认LOG动作会将日志记录到`/var/log/messages文件中,但是上例中使用的匹配条件过于宽泛,所以匹配到的报文数量将会非常之多,记录到的信息也不利于分析,所以在使用LOG动作时,匹配条件应该尽量写的精确一些,匹配到的报文数量也会大幅度的减少,这样冗余的日志信息就会变少,同时日后分析日志时,日志中的信息可用程度更高。

务必删除上例的规则,不然会产生大量的日志,占用大量磁盘空间!!!

从上面的示例中我们已经了解到,LOG动作会将报文的相关信息记录在/var/log/messages文件中,当然,我们也可以将相关信息记录在指定的文件中,以防止iptables的相关信息与其他日志信息相混淆,修改/etc/rsyslog.conf文件(或者/etc/syslog.conf),在rsyslog配置文件中添加如下配置即可。

vim /etc/rsyslog.conf

# 添加如下内容
kern.warning /var/log/iptables.log

# 重启rsyslog,/var/log/iptables.log会自动生成
systemctl restart rsyslog.service

然后设置如下防火墙规则:

iptables -t filter -F INPUT
iptables -t filter -I INPUT -s 192.168.126.39 -p tcp -m tcp --dport 22 -j LOG

效果如下:image-20220222161605932

然后查看/var/log/iptables.logimage-20220222162150725

注意:虽然会将日志写到/var/log/iptables.log中,但是/var/log/messages文件中还是会写入一样的日志。

LOG动作也有一些选项可以使用,常用的选项如下:

  • --log-level选项:可以指定记录日志的日志级别,可用级别有emerg,alert,crit,error,warning,notice,info,debug。
  • --log-prefix选项:可以给记录到的相关信息添加标签之类的信息,以便区分各种记录到的报文信息,方便在分析时进行过滤。但是:--log-prefix对应的值不能超过29个字符。

比如,我想要将主动连接22号端口的报文的相关信息都记录到日志中,并且把这类记录命名为want-in-from-port-22,则可以使用如下命令:

iptables -F INPUT
iptables -t filter -I INPUT -p tcp --dport 22 -m state --state NEW -j LOG --log-prefix "want-in-from-port-22"

效果如下:image-20220222162814403

此时查看/var/log/iptables.logimage-20220222162941365

1.9.2.3 SNAT

SNAT:源地址转换,在[1.8 Iptables作为网络防火墙](### 1.8 Iptables作为网络防火墙)中已经详细的说明了SNAT的使用方法和作用。主要是实现多个内网IP共享一个公网IP访问互联网。

1.9.2.4 DNAT

DNAT:目标地址转换,在[1.8 Iptables作为网络防火墙](### 1.8 Iptables作为网络防火墙)中也进行了详细的说明。主要是可以使外部服务器通过网关服务器的公网IP访问到内网环境中的服务。

1.9.2.5 MASQUERADE

MASQUERADE动作和SNAT相似,同样都是能够实现源地址转换,但是SNAT在实现源地址转换的时候必须要指定报文的源地址转换为哪个IP,而MASQUERADE不用指定明确的IP,会动态的将报文的源地址修改为指定网卡上可用的IP地址,实现动态的将源地址转换为可用的IP地址。示例如下:

iptables -t nat -I POSTROUTING -s 172.16.1.0/24 -o eth0 -j MASQUERADE

这样,iptables会动态获取eth0网卡的IP地址,并动态的将172.16.1.0/24网段的源地址转换为eth0网卡的IP。

可以把MASQUERADE理解为动态的、自动化的SNAT,如果没有动态SNAT的需求,没有必要使用MASQUERADE,因为SNAT更加高效

1.9.2.6 REDIRECT

使用REDIRECT动作可以在本机上进行端口映射。

比如,将本机的8080端口映射到本机的80端口上:

iptables -t nat -A PREROUTING -p tcp -m tcp --dport 8080 -j REDIRECT --to-ports 80

效果如下:image-20220222164147677

当其他服务器访问本机的8080端口时,会自动重定向到80端口:image-20220222164445841

image-20220222164335125

REDIRECT规则只能定义在PREROUTING链或者OUTPUT链中。

1.10 Iptables常用套路

1.10.1 规则的顺序非常重要

如果报文已经被前面的规则匹配到,IPTABLES则会对报文执行对应的动作,通常是ACCEPTDROP或者REJECT,报文被放行或拒绝以后,即使后面的规则也能匹配到刚才放行或拒绝的报文,也没有机会再对报文执行相应的动作了(前面规则的动作为LOG时除外),所以,针对相同服务的规则,更严格的规则应该放在前面。

1.10.2 当规则中有多个匹配条件时,条件之间默认存在的关系

如果一条规则中包含了多个匹配条件,那么报文必须同时满足这个规则中的所有匹配条件,报文才能被这条规则匹配到。

1.10.3 在不考虑1的情况下,应该将更容易被匹配到的规则放置在前面

如果有两条规则,分别针对sshd服务和web服务,但是一天之内,有2w个请求访问web服务,有200个请求访问sshd服务,那么应该把针对web服务的防火墙规则放在前面,针对sshd服务的防火墙规则放在后面,因为访问web服务的请求更高,规则放在前面能够提高匹配效率,浪费的资源会更少。

1.10.4 iptables作为网络防火墙要慎重考虑规则

当IPTABLES所在主机作为网络防火墙时,在配置规则时,应着重考虑方向性,双向都要考虑,从外到内,从内到外

1.10.5 iptables白名单

在配置IPTABLES白名单时,往往会将链的默认策略设置为ACCEPT,通过在链的最后设置REJECT规则实现白名单机制,而不是将链的默认策略设置为DROP,如果将链的默认策略设置为DROP,当链中的规则被清空时,管理员的请求也将会被DROP掉。