iptables 官方man文档: https://linux.die.net/man/8/iptables
iptables中文指南(比较详细): https://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html
说明:
本文测试基于系统环境: centOS 7
本文以实用的角度理解防火墙,不是官方文档的知识点罗列。
计算机领域中防火墙一般指的是网络(特指TCP/IP网络)防火墙,根据TCP/IP网络模型,防火墙可以处在不同的层,主要两种:普通的网络层防火墙,上层的应用防火墙,如WAF。
linux和windows操作系统中的防火墙,我们叫网络层防火墙,准确的说应该是传输层的,因为会处理TCP, UDP端口号,而不仅仅是IP。
网络层防火墙的作用: 包过滤,根据源IP,端口,目标IP端口,过滤数据包,允许通行或者禁止通行。
linux防火墙由内核netfiter实现,用户不能直接操作内核,提供了防火墙配置工具iptables和现在centos 7版本开始的firewalld工具,这两个工具只是防火墙的配置接口,内核都是netfiter。
iptables配置命令复杂,原始,难度较大,但支持配置全部的功能。
而firewalld做了更高级的封装,配置命令简单,但无法实现复杂的配置,要实现复杂的配置需要用rich-rule(富规则),以及更高级的direct命令(和iptables命令几乎一模一样了)。
iptables的功能:
iptables是网络层防火墙,必然支持基于ip和端口的过滤规则;
默认包过滤是没有状态的,即每个进出的数据包均视为一个独立的数据包。
支持扩展模块,通过扩展模块可以实现许多高级的功能 ,常用如下:
iptables防火墙的功能上还增加了修改数据包的功能,修改数据包最广泛的应用应该是NAT了, iptables支持DNAT, SNAT , 如果同时使用DNAT, SNAT可以实现端口转发的功能(原理会有实例说明)。
iptables 的NAT是有状态的NAT ,只需要配置发起请求时的转换规则,而返回的数据会自动对应转换回来。
其它更高级的修改数据包的应用没研究过。
任何一个网络主机处理数据必须有以下流程:
? 1.接收到数据:网卡接收到数据--> 路由判断数据是否是本机->1,本机:转给相应的上层应用 ->2, 目标不是本机, 再路由判断通过哪个网卡转发出去-->发出去
? 如果不允许数据转发,数据目标不是本机则直接丢弃。
? 2.本机上层应用要发送数据出去: 应用数据转给内核--> 路由判断从哪个网口发送出去-->发出去
实现原理:在不同数据流程节点挂勾子函数,过滤数据, 符合的放回数据包流中,不符合条件的数据包从流程移除。
iptables将数据转发的5个流程节点勾子依次对应为5个链,全部为大写字母:
iptables将功能分为4类,即为iptables四表 :
实际有5个表,而不是我们常说的4表,还有一个表是security,本文不讨论这个表。
不同的表可以应用到不同的链上,
filter: INPUT 、FORWARD 、OUTPUT
过滤目标或本地为源的数据:接收-INPUT 、发出-OUTPUT
过滤经本机转发的数据: FORWARD
nat : PREROUTING 、INPUT 、OUTPUT 、 POSTROUTING
2.1 SNAT: INPUT、 POSTROUTING
必须先路由, 所以不能在PREROUTING 做,在从本机发出前的最后一步再修改源IP为本机出接口IP,如果在路由前即刚接收到数据就修改源端口为出接口的IP是不合理的:
2.2 **DNAT: OUTPUT 、 PREROUTING **
必须在路由前做DNAT, 这个好理解,只有DNAT修改数据报为真实的目标IP ,后面的路由在正确选择,因为SNAT没有修改,也不影响之后流程处理。
2.3 **总结: 一般 SNAT在POSTROUTING做,SNAT在PREROUTING 做 **, OUTPUT是本机发出的数据,没怎么见过需要用到NAT的场景。
2.4 **同时进行SNAT和DNAT
mangle : 5链均适用, 没用过,不讨论
raw :PREROUTING 、 OUTPUT,没用过,不讨论
同一链上,如果有多个表的配置规则,优先处理次序依次为raw --> mangle --> nat --> filter
iptables 【-t 表名 】 操作 链名 【规则编号】 匹配规则 -j 处理动作
可选,不配置默认是 filter,
不同表只能使用允许的链名
iptables命令最复杂的部分就在匹配条件这部分
一级条件参数形式 -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 会自动加载相应协议的扩展模块,指定端口号是扩展模块的功能。
--dport 源端口号 [!]port[:port] ,--source-port 的简写,可以是端口范围
--sport 目标端口号 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
connlimit 连接数据限制,可以限制匹配规则的连接数量,比如限制SSH连接数据只能为3
multiport 端口使用集合指定 ,最多15个,
iprange 指定ip地址范围
time 时间匹配
limit 速率匹配 ,
使用令牌桶的算法,第个要转发的数据包要获取一个令牌才能转发,没有获取令牌的包,不匹配该规则,会转由下一条匹配,如果限速,紧跟后面要有一条规则丢弃数据。
string 匹配应用层数据中的字符串, 只是简单以字符串形式匹配应用层数据,不会识别应用协议,如果是加密的也不会解密,只能是应该层协议没有加密时有用,比如http
--string pattern
? 处理动作全部用大写字母
SNAT 源地址转换
--to-source [ipaddr[-ipaddr]][:port[-port]][:port][-port] 可以指定端口范围,如果不指定,默认尽可能不变更端口,但如果端口已经被其它链接占用,会选用另一个端口替换,默认的端口转换遵守以下规则:
TCP/UDP 端口作用为了0-511, 512-1024,1024以上这三个段,以上规则与之对应,不会出现源端口占用标准服务端口的情况:
比如,访问外部http服务,把源端口转换成了21 , 占用了FTP的端口,导致端口混乱(虽然技术上说也能通)
DNAT 目标地址转换
? Later Kernels (>= 2.6.11-rc1) 不再支持IP范围内的轮训转换,这个功能常做负载均衡用,也就是说centos7 开始不支持这一功能了, 不知道什么原因。
默认iptables配置规则只能当前生效,重启就没有了,需要用命令把规则放保存到文件,然后设置开机启动脚本加载配置文件
查看当前规则
[root@localhost ~]# iptables -vL --line-number
Chain INPUT (policy ACCEPT 9639 packets, 806K bytes)
num pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 5388 packets, 2808K bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 8262 packets, 1684K bytes)
num pkts bytes target prot opt in out source destination
[root@localhost ~]#
查看nat表 , 没有指定-t 默认filter表
[root@localhost ~]# iptables -t nat -vL --line-number
Chain PREROUTING (policy ACCEPT 1281 packets, 105K bytes)
num pkts bytes target prot opt in out source destination
1 6 312 DNAT tcp -- any any anywhere localhost.localdomain tcp dpt:rtsps to:192.168.31.12:22
Chain INPUT (policy ACCEPT 629 packets, 56218 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 296 packets, 22480 bytes)
num pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 296 packets, 22480 bytes)
num pkts bytes target prot opt in out source destination
1 1 52 SNAT tcp -- any any 10.100.90.200 192.168.31.12 tcp dpt:ssh to:192.168.31.1:1023
2 686 50843 SNAT all -- any any 192.168.31.0/24 anywhere to:10.100.93.202
清空规则
[root@localhost ~]# iptables -t nat -F
[root@localhost ~]# iptables -t nat -vL --line-number
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
[root@localhost ~]#
开放本地端口80
没有用 -A 是因为表中已有其它规则,一般最后一条是默认规则,实际中往往是插入到第一条比较常见
插入到第2条
iptables -t filter -I INPUT 1 -p tcp --dport 80 -j ACCEPT
插入到第2条
iptables -t filter -I INPUT 2 -p tcp --dport 80 -j ACCEPT
替换第2条
iptables -t filter -R INPUT 2 -p tcp --dport 80 -j ACCEPT
只允许指定源IP访问
iptables -t filter -R INPUT 2 -s 192.168.1.1 -p tcp --dport 80 -j ACCEPT
通过状态匹配防火墙
禁止本机主动发起的出站连接 (服务器上可以这么设置,因为服务器是让别人访问自身 ,而自己本身不需要发起对外的连接,可以防止反弹木马)
iptables -t filter -I OUTPUT -m multiport -m state --state NEW -j DROP
允许(非本机主动发起的)外部主机主动发起的对本机的连接
iptables -t filter -I OUTPUT -m multiport -m state --state ESTABLISHED,RELATED -j DROP
SNAT 代理上网, 允许源地址192.168.1.0/24 经本机上网 10.100.93.202为连通公网的IP
iptables -t nat -I POSTROUTING -s 192.168.1.0/24 -j SNAT --to-source 10.100.93.202
DNAT 将目标为本机IP 10.100.93.202 ,目标端口为 80 的数据转发到后端真实服务器 192.168.1.10的8000端口去
iptables -t nat -I PREROUTING -d 192.168.1.0/24 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.0:8000
接合 SNAT和DNAT实现端口转发
SNAT在数据发出时转换IP为本机出接口,DNAT在接收到数据时转换目标IP为后端真实服务器IP ,组合这两个特性,可以实现端口转发的功能。
假如有如下场景:
在外网的用户能访问到防火墙外网IP 10.100.0.20
防火墙内网IP和内网服务器可以互通,同时内网服务器与外网隔离,不能通信
用户要想直接访问内网服务器的一个端口。
解决方法:
此场景不能只用DNAT, 因为内网服务器与外网不通,返回给user的数据是无法出内网的。
user只能与防火墙能,数据包的源地址必须是防火墙的,所以还需要SNAT, 在从防火墙内网口发出时转换源地址为192.168.0.20 , 内网服务器返回数据,自然目标地址也就是192.168.0.20。
iptables nat是有链接状态的,返回的数据会自动反向转换,返回的数据经由以下过程:
防火墙内网口192.168.0.20 收到数据时,返向转换目标IP为真实的USER , 经路由后,由公网口
10.100.0.20发出时,反向转换源端口为防火墙自身端口 10.100.0.20.
通信完成。
此过程即为端口转发,当然有很多开源软件可以实现端口转发,但linux防火墙全部是在内核完成这些操作的,而使用其它软件自然数据是要经过用户空间,而且需要在公网端口建立tcp/udp监听才可以。
? 配置:
? 内网服务器端口22, 防火墙用端口 13322转发:
# DNAT
iptables -t nat -I PREROUTING -d 10.100.0.20 -p tcp --dport 13222 -j DNAT --to-destination 192.168.0.10:22
# SNAT
iptables -t nat -I POSTROUTING -d 192.168.0.10 --dport 22 -j SNAT --to-source 192.168.0.20
原文:https://www.cnblogs.com/wyf368/p/13633465.html