1. 基本概念
1.1. 4表5链
防火墙由很多规则组成,每个规则匹配产生不同的动作,这些规则按功能共划分出4个表,一个表由多个相同功能的规则组成:
- raw 控制NAT表中连接跟踪机制的启用状况
- mangle 修改数据
- filter 过滤
- nat 地址转换
在数据经过的各个路径上,设置了5个关键卡点,每个卡点上按顺序有多个规则,共组成5条规则链:
- PREROUTING: 外部数据刚进入
- INPUT: 经过路由决策,要进入本机的数据
- OUTPUT: 本机要出去的数据
- FORWARD: 经过路由决策,经过本机转发的数据
- 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