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