0%

iptables相关

1. 基本概念

1.1. 4表5链

防火墙由很多规则组成,每个规则匹配产生不同的动作,这些规则按功能共划分出4个表,一个表由多个相同功能的规则组成:

  1. raw 控制NAT表中连接跟踪机制的启用状况
  2. mangle 修改数据
  3. filter 过滤
  4. nat 地址转换

在数据经过的各个路径上,设置了5个关键卡点,每个卡点上按顺序有多个规则,共组成5条规则链:

  1. PREROUTING: 外部数据刚进入
  2. INPUT: 经过路由决策,要进入本机的数据
  3. OUTPUT: 本机要出去的数据
  4. FORWARD: 经过路由决策,经过本机转发的数据
  5. POSTROUTING: 发送出去的数据

外部数据进入本机,会经过 PREROUTING, INPUT链

本机数据出去,会经过 OUTPUT, POSTROUTING链

外部数据经过本机路由转发出去,会经过 PREROUTING, FORWARD, POSTROUTING链

控制的链
filter INPUT, FORWARD, OUTPUT
nat PREROUTING, INPUT, OUTPUT, POSTROUTING
mangle PREROUTING, INPUT, FORWARD, POSTROUTING
raw PREROUTING, OUTPUT
raw mangle nat filter
PREROUTING
INPUT
OUTPUT
FORWARD
POSTROUTING

在同一条链上,各个表中的规则会按顺序执行,表的优先级为:

raw –> mangle –> nat –> filter

可以自定义链,但是自定义的子链需要当做默认链中一个规则的动作才能被调用到。

1.2. 基本语法

1
iptables [-t table]  COMMAND [chain] CRETIRIA -j ACTION
  • -t: 指定要维护的表,默认filter
  • COMMAND: 子命令,定义对规则的管理
  • chain: 指定链
  • CRETIRIA: 匹配参数
  • ACTION: 要触发的动作

常用命令 COMMAND

选项 功能
-A 添加防火墙规则
-D 删除防火墙规则
-I 插入防火墙规则
-F 清空防火墙规则
-L 列出防火墙规则
-R 替换防火墙规则
-Z 清空防火墙数据表统计信息
-P 设置链默认规则
-E 给子链改名
-X 删除一个没有被引用、规则为空的子链

常用匹配参数 CRETIRIA

参数 功能
[!]-p 匹配协议,!表示取反
[!]-s 匹配源地址
[!]-d 匹配目标地址
[!]-i 匹配入站网卡接口
[!]-o 匹配出站网卡接口
[!]–sport 匹配源端口
[!]–dport 匹配目标端口
[!]–src-range 匹配源地址范围
[!]–dst-range 匹配目标地址范围
[!]–limit 匹配数据表速率
[!]–mac-source 匹配源MAC地址
[!]–state 匹配状态(INVALID, ESTABLISHED, NEW, RELATED)
[!]–string 匹配应用层字符串

常用动作

触发动作 功能
ACCEPT 允许数据包通过
DROP 丢弃数据包
REJECT 拒绝数据包通过
LOG 将数据包信息记录syslog日志
DNAT 目标地址转换
SNAT 源地址转换
MASQUERADE 地址欺骗
REDIRECT 重定向

内核按照顺序检查 iptables 防火墙规则,如果匹配,就执行相关动作, 停止向下继续查找,如果都没有匹配,就按默认处理

2. iptables 和 firewalld

  • 都是linux防火墙服务,早期的是 iptables,新的系统一般都是 firewalld。 firewalld 操作会反应到 iptables 规则。
  • iptables 只能一条一条规则添加,firewalld 支持将不同的规则组成区域(zone,共9个,默认public),在不同的网络环境使用不同的区域,快速切换。
  • 都可以用 systemctl 管理,firewalld 是 centos7自带的,可以直接使用 systemctl status firewalld, iptables 需要安装一个服务配置:
1
yum install -y iptables-services

然后就能用 systemctl 管理了。

  • iptables 和 firewalld 都是服务,iptables 和 firewall-cmd 都是用户命令行接口,用于控制这两个服务, 只不过 firewalld 的服务和前端是两个名字, iptables 是一个名字。
  • centos7 默认使用 firewalld, 使用 firewall-cmd 配置的规则,也能用 iptables 查看,反过来也一样。

3. iptables 例子

3.1. 导入导出当前规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ iptables-save
# Generated by iptables-save v1.4.21 on Sun Jun 12 08:08:48 2022
*filter
# 下面是 filter 表的规则

# filter 表中 INPUT 链默认规则是 ACCEPT, [0:0] 表示[packet, bytes], 当前有多少个包经过 filter 表的这个链
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [1437:138710]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
# Completed on Sun Jun 12 08:08:48 2022

# 保存到文件
$ iptables-save > ipt.save

# 从文件恢复
$ iptables-restore < ipt.save


# 重启机器后失效,需要保存到文件,重启时导入
# 这里会保存到 /etc/sysconfig/iptables, 相当于使用 iptables-save > /etc/sysconfig/iptables
$ service iptables save

# 保存到其他位置,需要重启的时候增加一个启动项,将配置恢复,一般是放到 /etc/rc.local 中

3.2. 查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 查看 filter 表所有规则, -v 显示统计值, -n 不解析地址, -L 列出规则
# 结果: policy 表示 filter 表 INPUT 链的默认规则是 ACCEPT
$ iptables -vnL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
2566 182K ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
0 0 ACCEPT icmp -- * * 0.0.0.0/0 0.0.0.0/0
6 438 ACCEPT all -- lo * 0.0.0.0/0 0.0.0.0/0
1 52 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
33 3006 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
0 0 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited

Chain OUTPUT (policy ACCEPT 2244 packets, 222K bytes)
pkts bytes target prot opt in out source destination


# 列出 filter 表 INPUT 链的所有规则, --line-numbers(有时候可以用--line匹配) 列出规则序号,方便中间插入时使用
iptables -vnL INPUT --line-numbers

# 列出 nat 表的所有规则
iptables -t nat -vnL

3.3. 增

1
2
3
4
5
6
7
8
# 在 filter 表 INPUT 链开头插入一条规则, 匹配源地址, 动作是丢弃报文. DROP是直接丢弃, REJECT 是会通知对端该报文被拒绝
$ iptables -t filter -I INPUT -s 192.168.1.145 -j DROP

# 在 filter 表 INPUT 链的第2个位置插入规则
$ iptables -t filter -I INPUT 2 -s 192.168.1.145 -j DROP

# 在最后增加规则
$ iptables -t filter -A INPUT -s 192.168.1.145 -j DROP

3.4. 删

1
2
3
4
5
# 删除 filter 表 INPUT 链第3条规则
$ iptables -t filter -D INPUT 3

# 删除 filter 表 INPUT 链所有规则
$ iptables -t filter -F INPUT

3.5. 改

1
2
3
4
5
# 改的时候,需要带上原来的规则匹配语句,这里的改,相当于删掉之前的语句,重写一个规则,所以即使有规则序号,也要写完整原来的规则
$ iptables -t filter -R INPUT 1 -s 192.168.1.146 -j REJECT

# 修改链的默认策略
iptables -t filter -P FORWARD DROP

3.4. 条件匹配

基本匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 匹配源地址
-s 192.168.1.145

# 指定多个源地址,逗号隔开, 会变成两条相邻的规则
-s 192.168.1.123,192.168.1.124

# 指定网段
-s 10.6.0.0/16

# 条件取反,只是规定了不是这个IP的会怎样,没有规定是这个IP会怎样
! -s 192.168.1.123

# 匹配目标地址
-d 192.168.1.101

# 一个规则多个条件,必须都满足才算匹配
-s 1.2.3.4 -d 2.3.4.5

# 匹配协议, tcp, udp, udplite, icmp, icmpv6,esp, ah, sctp, mh, 或者 -p all,默认是所有协议
-p tcp

# 匹配入口网卡, -o 匹配出口网卡,指定数据从哪个网卡出去
-i eth0

扩展匹配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# tcp: 匹配端口,必须用 -p 指定协议, 用 -m 指定扩展模块(协议名和模块名一致的话,可以省略 -m)
-p tcp -m tcp --dport 9999

# tcp: 反选
! --dport 22

# tcp: 匹配端口段,:22 表示0-22的段, 80: 表示 80以后的段, 22:25 表示 22-25的段,tcp模块只能指定连续的段
--dport 22:25

# tcp: 匹配tcp-flags,前一段表示要匹配的位,后一段表示哪一位必须位1。以下两条匹配效果一样,都匹配三次握手的第2个包。
-p tcp -m tcp --dport 22 --tcp-flags SYN,ACK,FIN,RST,URG,PSH SYN,ACK
-p tcp -m tcp --dport 22 --tcp-flags ALL SYN,ACK

# tcp: 匹配三次握手第一个包
-p tcp -m tcp --dport 22 --syn

# multiport: 匹配零散的端口段,需要用到 multiport 模块, 只能用于 tcp, udp协议
-p tcp -m multiport --dports 22,36,80

# iprange: 匹配IP地址段, --src-range, --dst-range
-m iprange --src-range 192.168.1.127-192.168.1.146

# string: 匹配字符串, --algo bm 指定匹配算法
-m string --algo bm --string "OOXX"

# time: 匹配时间段
-p tcp --dport 80 -m time --timestart 09:00:00 --timestop 18:00:00
-p tcp --dport 80 -m time --weekdays 6,7
-p tcp --dport 80 -m time --monthdays 22,23

# connlimit: 限制每个IP地址同时连接到服务器的数量,不能指定IP。限制每个ip不能连接超过2个ssh通道
-p tcp --dport 22 -m connlimit --connlimit-above 2

# limit: 限制单位时间内包速率,使用令牌桶算法进行限速, --limit 限制令牌产生速度, --limit-burst 限制令牌最大个数
# /second, /minute, /hour, /day
-p icmp -m limit --limit 10/minute --limit-burst 3

# state: 连接状态跟踪,tcp,udp,icmp 都有状态,状态有5种:
# NEW: 连接第一个包
# ESTABLISHED: NEW状态之后的包的状态,连接已建立
# RELATED: 相关联的连接
# INVALID: 无法被识别状态的包
# UNTRACKED: 未被跟踪的包,无法找到相关连接

4. 自定义子链

用于集合一组规则。

1
2
3
4
5
6
7
8
9
10
11
# 添加子链
-t filter -I IN_WEB -s 192.168.1.123 -j REJECT

# 必须在默认链中使用子链,子链才生效
-I INPUT -p tcp --dport 80 -j IN_WEB

# 给子链改名
-E IN_WEB WEB

# 删除子链
-X WEB

5. 动作

1
2
3
4
5
6
7
8
9
10
# -j REJECT --reject-with: 提示对方为什么会被拒绝, 默认是icmp-port-unreachable
# icmp-net-unreachable icmp-host-unreachable icmp-port-unreachable icmp-proto-unreachable icmp-net-prohibited icmp-host-pro-hibited icmp-admin-prohibited
-j REJECT --reject-with icmp-port-unreachable

# LOG: 记录匹配的数据包到日志 syslog 中, /var/log/messages, 不进行其他动作
-j LOG --log-level info --log-prefix 'want-in-from-port-22'

# SNAT, DNAT

# MASQUERADE 动态做SNAT,SNAT需要指定转换的目标地址,但有时候目标地址是动态的,用 MASQUERADE 可以自动选择可用地址进行转换.

6. firewalld 使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 基本操作
firewall-cmd --state # 显示状态
firewall-cmd --reload # 重新加载服务
firewall-cmd --runtime-to-permanent # 将当前防火墙规则永久保存
firewall-cmd --check-config # 检查配置正确性


# 区域操作
firewall-cmd --get-zones # 所有支持的区域
firewall-cmd --get-active-zones # 查看当前使用的区域信息
firewall-cmd --set-default-zone=public # 设置默认接口区域,立即生效无需重启

# 服务操作, 类似于将端口可视化,服务需要在配置文件中添加,/etc/firewalld 目录下有services文件夹
--add-service=smtp # 添加服务
--remove-service=smtp # 移除服务
firewall-cmd --get-services # 获取所有可以支持的服务列表


# 端口操作
firewall-cmd --add-port=443/tcp # 打开443/TCP端口,这里直接生效,不需要 --reload,但没有写入配置永久生效,可以执行 --runtime-to-permanent,写入配置文件
firewall-cmd --permanent --add-port=3690/tcp # 永久打开3690/TCP端口, 这里是写入到配置文件,并没有生效,需要 --reload
firewall-cmd --zone=public --add-port=0-65535/tcp --permanent # 打开所有端口
firewall-cmd --remove-port 9999/tcp
firewall-cmd --list-ports

# FirewallD包括一种直接模式,直接用iptables的规则,例如打开TCP协议的9999端口
firewall-cmd --direct -add-rule ipv4 filter INPUT 0 -p tcp --dport 9000 -j ACCEPT
firewall-cmd --reload


# 限制IP 192.168.0.200 访问 80 的tcp端口
firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.0.200" port protocol="tcp" port="80" reject"
firewall-cmd --permanent --remove-rich-rule="rule family="ipv4" source address="192.168.0.200" port protocol="tcp" port="80" accept"

# 限制IP 192.168.0.200 访问
firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.0.200" reject"

# 限制 IP 段访问
firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.0.0/24" reject"

7. 一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 启动,加开机启动项
systemctl start firewalld
systemctl enable firewalld


# 启动后,默认值打开 ssh 端口,下面打开所有端口的访问
firewall-cmd --permanent --add-port=0-65535/tcp
firewall-cmd --permanent --add-port=0-65535/udp
firewall-cmd --reload

# 限制某个IP访问
firewall-cmd --permanent --add-rich-rule="rule family="ipv4" source address="192.168.0.200" reject"
firewall-cmd --reload

# 以下可以删除限制
firewall-cmd --permanent --remove-rich-rule="rule family="ipv4" source address="192.168.0.200" reject"
firewall-cmd --reload

参考

https://www.zsythink.net/archives/1199