iptables防火墙详解
1. 什么是iptables
iptables是Linux平台下的包过滤防火墙,与大多数的Linux软件一样,这个包过滤防火墙是免费的,它可以代替昂贵的商业防火墙解决方案,完成封包过滤、封包重定向和网络地址转换(NAT)等功能。
规则(rules)其实就是网络管理员预定义的条件,规则一般的定义为“如果数据包头符合这样的条件,就这样处理这个数据包”。规则存储在内核空间的信息包过滤表中,这些规则分别指定了源地址、目的地址、传输协议(如TCP、UDP、ICMP)和服务类型(如HTTP、FTP和SMTP)等。当数据包与规 则匹配时,iptables就根据规则所定义的方法来处理这些数据包,如放行(accept)、拒绝(reject)和丢弃(drop)等。配置防火墙的主要工作就是添加、修改和删除这些规则。
2. 理解本机数据路由决策
网络数据总是会流入、流出的,即使是本机的客户端和服务端进程间通信,也需要从一个套接字流出、另一个套接字流入,只不过这些数据无需路由、无需经过物理网卡(走的是LoopBack)。
- 当接收外界发送的数据时,在数据从网卡流入后需要对它做路由决策,根据其目标决定是流入本机数据还是转发给其他主机,如果是流入本机的数据,则数据会从内核空间进入用户空间(被应用程序接收、处理)。
- 当用户空间响应(应用程序生成新的数据包)时,响应数据包是本机产生的新数据,在响应包流出之前,需要做路由决策,根据目标决定从哪个网卡流出。
- 如果不是流入本机的,而是要转发给其他主机的,则必然涉及到另一个流出网卡,此时数据包必须从流入网卡完整地转发给流出网卡,这要求Linux主机能够完成这样的转发。(ip_forward未开启,数据包无法转发而被丢弃)
Tips:Linux主机默认未开启ip_forward功能!Linux主机和路由器的不同就是路由器本身就是为了转发数据包,所以路由器内部默认就能在不同网卡间转发数据包,而Linux主机默认则不能转发。
一个例子的理解
Linux主机1有两张网卡eth0:10.0.0.61,eth1:172.16.1.61。Linux主机2有一张网卡,IP为10.0.0.5,网关10.0.0.5。Linux主机2能不能直接ping通172.16.1.61?答案是可以的。Linux主机2查询路由表无匹配路由条目后将数据包发往网关。网关即Linux主机1从eth0接收数据包。内核分析发现目标地址为本机地址,直接产生数据包进行回应10.0.0.5,根据Linux主机1的路由表策略,数据走的eth0网卡。
在此过程中,没有进行数据包转发过程,因为流出的响应包是新产生的,而非原来流入的数据包。如果流入和流出的包是一样的(或者稍作修改),则数据流入后不能进入用户空间,而是直接通过内核转发给另一个网卡。数据包从网卡1交给网卡2,这个过程就是转发,在Linux主机上由ip_forward进行控制。例如,网卡1所在网段主机ping网卡2所在主机时,数据包流入网卡1后就需要转交给网卡2,然后从网卡2流出。
Tips:IP地址是属于内核的(不仅如此,整个tcp/ip协议栈都属于内核,包括端口号)
3. iptables和netfilter的关系
iptables和netfilter的关系是一个很容易让人搞不清的问题。很多的知道iptables却不知道 netfilter。iptables只是管理控制netfilter的工具,可以使用该工具进行相关规则的制定以及其他的动作。iptables是用户层的程序,netfilter是内核空间的。真正实现防火墙功能的是 netfilter,它是Linux内核中实现包过滤的内部结构。
3.1 netfilter的结构
netfilter自己维护一个内存块,在此内存块中有4个表:filter表、NAT表、mangle表和raw表。在每个表中有相应的链,链中存放的是一条条的规则,规则就是过滤防火的语句或者其他功能的语句。也就是说表是链的容器,链是规则的容器。实际上,每个链都只是一个hook函数(钩子函数)而已。
Tips:要使netfilter能够工作,就需要将所有的规则读入内存中。
3.2 四表五链
filter表:netfilter中最重要的表,负责过滤数据包,也就是防火墙实现"防火"的功能。filter表中只有OUTPUT/FORWARD/INPUT链。
NAT表:实现网络地址转换的表。可以转换源地址、源端口、目标地址、目标端口。NAT表中的链是PREROUTING/POSTROUTING/OUTPUT。
mangle表:一种特殊的表,通过mangle表可以实现拆解报文、做出修改、重新封装。mangle表中包含所有的链。
raw表:加速数据包穿过防火墙的表,也就是增强防火墙性能的表。只有PREROUTING/OUTPUT表。
Tips:用的多的才是filter表和NAT表!
通过下图来理解这五条默认的规则链
从上图可知,不考虑特殊情况的话,一个数据包只会经过下面三个路径中的一个:
- A:主机收到目的 IP 是本机的数据包
- B:主机收到目的 IP 不是本机的数据包
- C:本机发出去的数据包
Tips:NAT表中OUTPUT链是本机发出的数据,很少需要用到NAT的场景,忽略即可。
路径 A, 从外界到达防火墙的数据包,先被NAT表的PREROUTING规则链处理(是否修改数据包地址等),之后会进行路由选择(判断该数据包应该发往何处),如果数据包的目标主机是防火墙本机。那么内核将其传给filter表的INPUT规则链进行处理(决定是否允许通过等),通过以后再交给系统上层的应用程序(比如Apache服务器)进行响应。
路径 B, 来自外界的数据包到达防火墙后,首先被NAT表的PREROUTING规则链处理,之后会进行路由选择,如果数据包的目标地址是路由表中的其它外部地址,则内核将其传递给filter表的FORWARD规则链进行处理(是否转发或拦截),然后再交给NAT表的POSTROUTING规则链(是否修改数据包的地址等)进行处理。
路径 C,数据包由 Linux 主机向外发送,比如响应客户端的请求要求,或者是 Linux 主机主动发送出去的数据包,都会通过路径 C。它会先进行路由判断,在确定了输出的路径后,再通过 filter 表的 OUTPUT 链来传送。当然,最终还是会经过 nat 表的 POSTROUTING 链。
总结规律
filter 表主要跟进入 Linux 主机的数据包有关,如下:
- INPUT:主要与想要进入 Linux 主机的数据包有关
- OUTPUT:主要与 Linux 主机所要发送出去的数据包有关
- FORWARD:与 Linux 主机没有关系,它可以对数据包进行转发
nat表主要在进行来源与目的之 IP 或 port 的转换,如下:
- PREROUTING:在进行路由判断之前所要执行的规则(DNAT目的地址转换)
- POSTROUTING:在进行路由判断之后所要执行的规则(SNAT源地址转换)
- OUTPUT:与发送出去的数据包有关
3.3 规则的行为
规则存放在特定表中的链上,链上的每条规则包含下面两部分的信息:
-
Matching
- 就是如何匹配一个数据包,匹配条件很多,比如协议类型、源/目的IP、源/目的端口、in/out接口、包头里面的数据以及连接状态等,这些条件可以任意组合从而实现复杂情况下的匹配。
-
Targets
- 就是找到匹配的数据包之后怎么办,会有什么动作。有下面几种:
- DROP:直接将数据包丢弃,不再进行后续的处理。
- ACCEPT:同意数据包通过,继续执行后续的规则(rule)。
- RETURN:跳出当前链,该链后续的规则不再执行。
- QUEUE:将数据包放入用户空间的队列,供用户空间的程序处理
- 跳转到其他用户自定义的链继续执行
- 就是找到匹配的数据包之后怎么办,会有什么动作。有下面几种:
Tips:最常用的数据包处理方式还是DROP,ACCEPT。
4. iptables使用方法
4.1 iptables命令
iptables 【-t 表名】 操作 链名 【规则编号】 匹配规则 -j 处理动作
-A 在指定链的末尾添加(append)一条新的规则
-D 删除(delete)指定链中的某一条规则,可以按规则序号和内容删除
-I 在指定链中插入(insert)一条新的规则,默认在第一行添加
-R 修改、替换(replace)指定链中的某一条规则,可以按规则序号和内容替换
-L 列出(list)指定链中所有的规则进行查看
-E 重命名用户定义的链,不改变链本身
-F 清空(flush)
-N 新建(new-chain)一条用户自己定义的规则链
-X 删除指定表中用户自定义的规则链(delete-chain)
-P 设置指定链的默认策略(policy)
-Z 将所有表的所有链的字节和数据包计数器清零
-n 使用数字形式(numeric)显示输出结果
-v 查看规则表详细信息(verbose)的信息
-V 查看版本(version)
-h 获取帮助(help)
4.2 表名和链名
表名:filter、nat、mangle、raw
链名:不同表只能使用允许的链名
- PREROUTING
- INPUT
- FORWARD
- OUTPUT
- POSTROUTING
4.3 操作
- -A 链中末尾添加规则
- -I 链名 【规则编号】 如果没有规则编号,插入到第一条的位置,有规则编号,插入到指定编号位置,原编号及之后的规则依次下移
- -R 链名 规则编号 必须输入规则编号,替换该编号的规则
- -D 链名 规则编号 必须输入规则编号,删除该编号的规则
4.4 匹配条件
一级条件参数形式 -option , 一级参数可能包含二级参数, 二级参数必须紧跟在主参数后写, 形式为 --option 两个 “--”。
-
TCP/IP匹配条件,IP 和端口号
- -s 源IP IP可以是单个IP , 也加掩码 配置网段 如192.168.1.1/24, 但不能是连续ip,如 192.168.1.1-192.168.1.20 (连续ip需要扩展模块)
- -d 目标IP IP可以是单个IP , 也加掩码 配置网段 如192.168.1.1/24, 但不能是连续ip,如 192.168.1.1-192.168.1.20
-
-i 网卡名 数据进入的网卡
-
-0 网卡名 数据流出的网卡
-
-p 协议名 tcp 、udp、icmp 等等, 指定协议名后才能进一步指定端口号,其实-p 会自动加载相应协议的扩展模块,指定端口号是扩展模块的功能。
- --sport 源端口号 port[:port] ,--source-port 的简写,可以是端口范围
- --dport 目标端口号 port[:port] --destination-port的简写, 可以是端口范围
- --tcp-flags mask comp
- mask comp 例 SYN,ACK,FIN,RST SYN 匹配 SYN标志必须为1, ACK,FIN,RST必须为0, 其它标志不检查的数据包。
-
-m 扩展模块
-
state
基于状态的匹配规则, 与特定的协议没有关系,可以是TCP, UDP , 状态也不是指TCP协议连接状态。
对于TCP来说,第一个连接请求SYN包状态为 NEW , 之后的全部为 ESTABLISHED 。 这个简单的规则是非常有用的,用于区分连接发起的方向,是从内到外还是从外到内,而其它的匹配规则都无法识别连接的发起方向
这个模块我认为是最有用的,关于内核如何跟踪、标识各个协议的链接状态,这个地址里有详细的介绍:https://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html
- --state 状态
- NEW 新发起的连接请求,第一次讲求的数据报为NEW状态
- ESTABLISHED 同一连接第一次请求之后的数据报均是该状态
- RELATED 第一请求,但是该请求是由已建立的其它连接发起的,典型应用 FTP的数据传输,数据传输连接是由已建立的FTP控制连接发起的新连接,使用这个需要加载
- INVALID 无效数据包,数据包不合法
- --state 状态
-
connlimit
连接数据限制,可以限制匹配规则的连接数量,比如限制SSH连接数据只能为3
-
--connlimit-upto n 连接数小于等于n
-
--connlimit-above n 连接数大于等于n
-
-
multiport
端口使用集合指定 ,最多15个。-
--sports port,port,port 或者 port:port 连续范围的port
-
--dports port,port,port 或者 port:port 连续范围的port
-
-
iprange 指定ip地址范围
-
--src-range ip1-ip2
-
--dst-range ip1-ip2
-
-
time 时间匹配
-
--timestart 开始日期 yyyy-mm-ddThh:mm:ss 例 1990-01-01T11:30:00 注意J日期和时间中间有个大写T,默认 1970-01-01T00:00:00
-
--timestop 结束日期 yyyy-mm-ddThh:mm:ss 例 1990-01-01T11:30:00 注意J日期和时间中间有个大写T,默认 2038-01-19T04:17:07
-
--datestart 结束时间 hh:mm:ss 例 11:30:00, 默认00:00:00
-
--datestop 结束时间 hh:mm:ss 例 11:30:00, 默认23:59:59
-
--monthdays 日期 1-31, 可以是集合,如 1,2,5,9
-
--weekdays 星期,1-7 , 可以是集合,如 1,3,5 1是星期一
-
-
limit 速率匹配
使用令牌桶的算法,每个要转发的数据包要获取一个令牌才能转发,没有获取令牌的包,不匹配该规则,会转由下一条匹配,如果限速,紧跟后面要有一条规则丢弃数据。
- --limit rate n[/second|/minute/hour/day] 速率限制 , 单位时间允许生成的令牌数据,也即允许转发的数据报数量, 注意: 不是带宽,不是带宽,当然通过限制包的数据也会间接限制了带宽速率,包大小*包数=带宽数。 默认3/hour
- --limit-burst n 初始令牌数据, 即初始允许不受限制发送的数据量,初始令牌用完,后面要等--limit 指定的单位时间生成的新令牌填充。
-
string
- 匹配应用层数据中的字符串, 只是简单以字符串形式匹配应用层数据,不会识别应用协议,如果是加密的也不会解密,只能是应该层协议没有加密时有用,比如http
- --string pattern
-
4.5 处理动作
filter表动作
- ACCEPT 允许
- DROP 直接丢弃
- REJECT 拒绝 ,丢弃同时返回ICMP消息
- LOG 日志记录 , 不会终止规则匹配,也就是说该动作只记录日志,至于数据包是否被转发,会继续匹配后续规则
NAT表动作
- SNAT 源地址转换
- DNAT 目标地址转换
4.6 总结
5. 使用iptables
iptalbes 是基于内核的,和 iptables.service 没有关系,对于 centOS 7 来讲,不用安装任何工具包就可以使用 iptable 命令添加的防火墙规则,只是添加的规则是临时的,基于内存的,会在系统重启前消失,所以需要 iptables.service,firewalld.service 来对添加的规则进行保存。在系统重启后重载对应的防火墙规则,在系统关机时卸载对应的规则。
5.1 安装iptables管理工具
yum install -y iptables-services
#关闭firewalld
systemctl stop firewalld
systemctl disable firewalld
#启动iptables管理
systemctl enable iptables.service
systemctl start iptables.service
#加载防火墙内核选项
modprobe ip_tables
modprobe iptable_filter
modprobe iptable_nat
modprobe ip_conntrack
modprobe ip_conntrack_ftp
modprobe ip_nat_ftp
modprobe ipt_state
#永久加载
cat >>/etc/rc.local<<EOF
modprobe ip_tables
modprobe iptable_filter
modprobe iptable_nat
modprobe ip_conntrack
modprobe ip_conntrack_ftp
modprobe ip_nat_ftp
modprobe ipt_state
EOF
#检查加载的内容
lsmod |egrep 'filter|nat|ipt'
5.2 iptables的保存和恢复
#保存
iptables–save > /etc/iptables/iptables.rules
#恢复
iptables–restore < /etc/iptables/iptables.rules
5.3 查看防火墙当前的规则
-t 指定表
-n使用数字形式显示输出结果
-L列出该表中链的规则情况
[root@ms01 ~]# iptables -t filter -nL
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain FORWARD (policy ACCEPT)
target prot opt source destination
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
显示表下的某个链的规则情况,直接在-L后加链名
[root@ms01 ~]# iptables -t filter -nL INPUT
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0
ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
REJECT all -- 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
显示规则编号,加上--line-numbers
[root@ms01 ~]# iptables -t filter -nL INPUT --line-numbers
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 DROP tcp -- 10.0.0.5 0.0.0.0/0 tcp dpt:22
2 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
3 ACCEPT icmp -- 0.0.0.0/0 0.0.0.0/0
4 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0
5 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
5.4 设置表的默认规则
#默认规则就是不添加-j指定规则行为
iptables -P INPUT DROP
iptables -P FORWARD DROP
5.5 禁止某主机连入ssh
#如要禁止某网段,直接写成网段形式
[root@ms01 ~]# iptables -t filter -I INPUT -s 10.0.0.5 -p tcp --dport 22 -j DROP
[root@ms01 ~]# iptables -nL
Chain INPUT (policy ACCEPT)
target prot opt source destination
DROP tcp -- 10.0.0.5 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
5.6 禁止某主机ping
[root@ms01 ~]# iptables -t filter -A INPUT -s 10.0.0.5 -p icmp -j DROP
5.7 允许指定多个端口连入
[root@ms01 ~]# iptables -t filter -I INPUT -s 10.0.0.5 -p tcp -m multiport --dport 80,43,22 -j ACCEPT
[root@ms01 ~]# iptables -t filter -nL INPUT
Chain INPUT (policy ACCEPT)
target prot opt source destination
ACCEPT tcp -- 10.0.0.5 0.0.0.0/0 multiport dports 80,43,22
DROP tcp -- 10.0.0.5 0.0.0.0/0 tcp dpt:22
DROP icmp -- 10.0.0.5 0.0.0.0/0
5.8 删除指定链的某条规则
[root@ms01 ~]# iptables -t filter -nL INPUT --line-numbers
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT tcp -- 10.0.0.5 0.0.0.0/0 multiport dports 80,43,22
2 DROP tcp -- 10.0.0.5 0.0.0.0/0 tcp dpt:22
3 DROP icmp -- 10.0.0.5 0.0.0.0/0
[root@ms01 ~]# iptables -t filter -D INPUT 1
[root@ms01 ~]# iptables -t filter -nL INPUT --line-numbers
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 DROP tcp -- 10.0.0.5 0.0.0.0/0 tcp dpt:22
2 DROP icmp -- 10.0.0.5 0.0.0.0/0
Tips:本文部分内容参考骏马金龙、sparkdev、wyf368等博主,感谢提供技术干货知识!