iptables 不仅仅是在传统的防火墙、NAT 等功能出现,在今天流行的的 Docker、Kubernetes、Istio 项目中也经常能见着对它的身影。所以,深入理解 iptables 工作原理是非常有价值的事情

一、Iptables 原理

Netfilter 是 Linux 内核中一个对数据 包进行控制、修改和过滤(manipulation and filtering)的框架。它在内核协议栈中设置了若干 hook 点,以此对数据包进行拦截、过滤或其他处理。 Iptables 是配置 Netfilter 过滤功能的用户空间工具。 netfilter 才是防火墙真正的安全框架(framework),netfilter 位于内核空间。iptables 其实是一个命令行工具,位于用户空间,我们用这个工具操作真正的框架。Iptable 根据规则所定义的方法来处理数据包,如放行(accept)、拒绝(reject)和丢弃(drop)等。 iptables 包含 4个表,5个链。其中表是按照对数据包的操作区分(过滤, NAT等)的,链是按照不同的 Hook 点来区分的,表和链实际上是netfilter的两个维度。
iptables 的四个表分别是 filter,mangle,nat,raw,默认表是filter。

filter 表:用来对数据包进行过滤,具体的规则要求决定如何处理一个数据包。
nat 表:主要用来修改数据包的 IP 地址、端口号信息。
mangle 表:主要用来修改数据包的服务类型,生存周期,为数据包设置标记,实现流量整形、策略路由等。
raw 表:主要用来决定是否对数据包进行状态跟踪。

iptables 的五个链分别是 PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING。

input 链:当收到访问本机地址的数据包时,将应用此链中的规则。
output 链:当本机向外发送数据包时,将应用此链中的规则。
forward 链:当收到需要转发给其他地址的数据包时,将应用此链中的规则,注意如果需要实现forward转发需要开启Linux内核中的ip_forward功能。
prerouting 链:在对数据包做路由选择之前,将应用此链中的规则。
postrouting 链:在对数据包做路由选择之后,将应用此链中的规则。

数据包流向:

微信图片_20230419135810.png
数据接收过程走的是 1 和 2,发送过程走的是 4 、5,转发过程是 1、3、5

二、Iptables 基本使用

1、查询规则

iptables -t filter -nvxL DOCKER  --line
-t:表名
-n:不解析IP地址
-v:会显示出计数器的信息,数据包的数量和大小
-x:选项表示显示计数器的精确值
--line-numbers:显示规则的序号(简写为--line)
-L:链名

其中 DOCKER 为链名,不写则显示所有链

2、增加规则

在指定表的指定链的尾部添加一条规则,-A 选项表示在对应链的末尾添加规则,省略 -t 选项时,表示默认操作 filter 表中的规则: 命令语法:iptables -t 表名 -A 链名 匹配条件 -j 动作

iptables -t filter -A INPUT -s 192.168.1.146 -j DROP

在指定表的指定链的首部添加一条规则,-I 选型表示在对应链的开头添加规则: 命令语法:iptables -t 表名 -I 链名 匹配条件 -j 动作

iptables -t filter -I INPUT -s 192.168.1.146 -j ACCEPT

在指定表的指定链的指定位置添加一条规则: 命令语法:iptables -t 表名 -I 链名 规则序号 匹配条件 -j 动作

iptables -t filter -I INPUT 5 -s 192.168.1.146 -j REJECT

3、删除规则

按照规则序号删除规则,删除指定表的指定链的指定规则,-D 选项表示删除对应链中的规则。示例表示删除filter表中INPUT链中序号为3的规则。: 命令语法:iptables -t 表名 -D 链名 规则序号

iptables -t filter -D INPUT 3

按照具体的匹配条件与动作删除规则,删除指定表的指定链的指定规则。示例表示删除filter表中INPUT链中源地址为192.168.1.146并且动作为DROP的规则。: 命令语法:iptables -t 表名 -D 链名 匹配条件 -j 动作

iptables -t filter -D INPUT -s 192.168.1.146 -j DROP

删除指定表的指定链中的所有规则,-F选项表示清空对应链中的规则: 命令语法:iptables -t 表名 -F 链名

iptables -t filter -F INPUT

4、修改规则

修改指定表中指定链的指定规则,-R 选项表示修改对应链中的规则,使用 -R 选项时要同时指定对应的链以及规则对应的序号,并且规则中原本的匹配条件不可省略。示例表示修改filter表中INPUT链的第3条规则,将这条规则的动作修改为ACCEPT, -s 192.168.1.146为这条规则中原本的匹配条件,如果省略此匹配条件,修改后的规则中的源地址可能会变为0.0.0.0/0: 命令语法:iptables -t 表名 -R 链名 规则序号 规则原本的匹配条件 -j 动作

iptables -t filter -R INPUT 3 -s 192.168.1.146 -j ACCEPT

设置指定表的指定链的默认策略(默认动作): 命令语法:iptables -t 表名 -P 链名 动作

iptables -t filter -P FORWARD ACCEPT

5、保存规则

当我们对规则进行了修改以后,如果想要修改永久生效,必须使用下面命令保存规则:

service iptables save

改动后的规则将会写入到 /etc/sysconfig/iptables 文件。还有一种方式可以保存,就是使用 iptables-save 命令。使用 iptables-save 并不能保存当前的 iptables 规则,但是可以将当前的 iptables 规则以”保存后的格式”输出到屏幕上,再配合重定向:

iptables-save > /etc/sysconfig/iptables

6、匹配条件

当规则中同时存在多个匹配条件时,多个条件之间默认存在”与”的关系,即报文必须同时满足所有条件,才能被规则匹配。 -s/-d 用于匹配报文的源地址,可以同时指定多个源地址,每个IP之间用逗号隔开,也可以指定为一个网段。

#示例如下

iptables -t filter -I INPUT -s 192.168.1.111,192.168.1.118 -j DROP iptables -t filter -I INPUT -s 192.168.1.0/24 -j ACCEPT iptables -t filter -I INPUT ! -s 192.168.1.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.1.146 -j ACCEPT iptables -t filter -I INPUT ! -p udp -s 192.168.1.146 -j ACCEPT

-i 用于匹配报文是从哪个网卡接口流入本机的,由于匹配条件只是用于匹配报文流入的网卡,所以在 OUTPUT 链与 POSTROUTING 链中不能使用此选项。

#示例如下

iptables -t filter -I INPUT -p icmp -i eth4 -j DROP iptables -t filter -I INPUT -p icmp ! -i eth4 -j DROP

-o 用于匹配报文将要从哪个网卡接口流出本机,于匹配条件只是用于匹配报文流出的网卡,所以在 INPUT 链与 PREROUTING 链中不能使用此选项。

#示例如下

iptables -t filter -I OUTPUT -p icmp -o eth4 -j DROP iptables -t filter -I OUTPUT -p icmp ! -o eth4 -j DROP

7、扩展匹配条件

tcp扩展模块

常用的扩展匹配条件如下:

–sport:用于匹配 tcp 协议报文的源端口,可以使用冒号指定一个连续的端口范围。
–dport:用于匹配 tcp 协议报文的目标端口,可以使用冒号指定一个连续的端口范围。
–tcp-flags:用于匹配报文的tcp头的标志位。
–syn:用于匹配 tcp 新建连接的请求报文,相当于使用 –tcp-flags SYN,RST,ACK,FIN SYN。

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

#示例如下

iptables -t filter -I OUTPUT -d 192.168.1.146 -p tcp -m tcp --sport 22 -j REJECT iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport 22:25 -j REJECT iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport :22 -j REJECT iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m tcp --dport 80: -j REJECT iptables -t filter -I OUTPUT -d 192.168.1.146 -p tcp -m tcp ! --sport 22 -j ACCEPT 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 iptables -t filter -I INPUT -p tcp -m tcp --dport 22 --syn -j REJECT

udp 扩展模块

常用的扩展匹配条件:

–icmp-type:匹配icmp报文的具体类型。

#示例

iptables -t filter -I INPUT -p icmp -m icmp --icmp-type 8/0 -j REJECT iptables -t filter -I INPUT -p icmp --icmp-type 8 -j REJECT iptables -t filter -I OUTPUT -p icmp -m icmp --icmp-type 0/0 -j REJECT iptables -t filter -I OUTPUT -p icmp --icmp-type 0 -j REJECT iptables -t filter -I INPUT -p icmp --icmp-type "echo-request" -j REJECT

multiport 扩展模块

常用的扩展匹配条件如下:

-p tcp -m multiport –sports 用于匹配报文的源端口,可以指定离散的多个端口号,端口之间用”逗号”隔开。
-p udp -m multiport –dports 用于匹配报文的目标端口,可以指定离散的多个端口号,端口之间用”逗号”隔开。

#示例如下

iptables -t filter -I OUTPUT -d 192.168.1.146 -p udp -m multiport --sports 137,138 -j REJECT iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m multiport --dports 22,80 -j REJECT iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m multiport ! --dports 22,80 -j REJECT iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m multiport --dports 80:88 -j REJECT iptables -t filter -I INPUT -s 192.168.1.146 -p tcp -m multiport --dports 22,80:88 -j REJECT

iprange 模块

包含的扩展匹配条件如下:

–src-range:指定连续的源地址范围。
–dst-range:指定连续的目标地址范围。

#示例

iptables -t filter -I INPUT -m iprange --src-range 192.168.1.127-192.168.1.146 -j DROP iptables -t filter -I OUTPUT -m iprange --dst-range 192.168.1.127-192.168.1.146 -j DROP iptables -t filter -I INPUT -m iprange ! --src-range 192.168.1.127-192.168.1.146 -j DROP

string 模块

常用扩展匹配条件如下:

–algo:指定对应的匹配算法,可用算法为bm、kmp,此选项为必需选项。
–string:指定需要匹配的字符串

我们想要达到的目的是,如果报文中包含某些需要屏蔽的字符,我们就拒绝报文进入本机:

#示例

iptables -t filter -I INPUT -m string --algo bm --string "屏蔽我" -j REJECT

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

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

limit 模块

connlimit 模块是对连接数量进行限制的,limit 模块是对”报文到达速率”进行限制的。用大白话说就是,如果我想要限制单位时间内流入的包的数量,就能用 limit 模块。我们可以以秒为单位进行限制,也可以以分钟、小时、天作为单位进行限制。常用的扩展匹配条件如下:

–limit-burst:类比”令牌桶”算法,此选项用于指定令牌桶中令牌的最大数量。
–limit:类比”令牌桶”算法,此选项用于指定令牌桶中生成新令牌的频率,可用时间单位有second、minute 、hour、day。

示例表示限制外部主机对本机进行ping操作时,本机最多每6秒中放行一个ping包

#示例,注意,如下两条规则需配合使用

#令牌桶中最多能存放3个令牌,每分钟生成10个令牌(即6秒钟生成一个令牌)。 iptables -t filter -I INPUT -p icmp -m limit --limit-burst 3 --limit 10/minute -j ACCEPT #默认将icmp包丢弃 iptables -t filter -A INPUT -p icmp -j REJECT

state 扩展模块

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

  • NEW: 连接中的第一个包,状态就是 NEW,我们可以理解为新连接的第一个包的状态为 NEW
  • ESTABLISHED: 我们可以把 NEW 状态包后面的包的状态理解为 ESTABLISHED,表示连接已建立
  • RELATED: 有关系的
  • INVALID: 如果一个包没有办法被识别,或者这个包没有任何状态,那么这个包的状态就是 INVALID,我们可以主动屏蔽状态为 INVALID 的报文
  • UNTRACKED: 报文的状态为 untracked 时,表示报文未被追踪,当报文的状态为 Untracked 时通常表示无法找到相关的连接 只有回应我们的报文能够通过防火墙,如果是别人主动发送过来的新的报文,则无法通过防火墙:

iptables -t filter -I INPUT -m state --state ESTABLISHED -j ACCEPT

8、自定义链

1、创建自定义链 #在filter表中创建IN_WEB自定义链

iptables -t filter -N IN_WEB

2、引用自定义链 #在INPUT链中引用刚才创建的自定义链

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

3|重命名自定义链 #将IN_WEB自定义链重命名为WEB

iptables -E IN_WEB WEB

4、删除自定义链 删除自定义链需要满足两个条件: 1、自定义链没有被引用。 2、自定义链中没有任何规则。

#第一步:清除自定义链中的规则 iptables -t filter -F WEB #第二步:删除自定义链 iptables -t filter -X WEB

9、LOG 动作

LOG 动作默认会将报文的相关信息记录在/var/log/message文件中,当然,我们也可以将相关信息记录在指定的文件中,以防止 iptables 的相关信息与其他日志信息相混淆,修改 /etc/rsyslog.conf 文件(或者 /etc/syslog.conf),在 rsyslog 配置文件中添加如下配置即可:

kern.warning /var/log/iptables.log

完成上述配置后,重启rsyslog服务(或者syslogd):

service rsyslog restart

LOG 动作也有自己的选项,常用选项如下:

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

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

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