Linux Iptables & Firewalls

本文最后更新于 2025年1月27日 下午

Iptables


什么是 iptables

Linux 系统在内核中提供了对报文数据包过滤和修改的官方项目名为 Netfilter,它指的是 Linux 内核中的一个框架,它可以用于在不同阶段将某些钩子函数(hook)作用域网络协议栈。Netfilter 本身并不对数据包进行过滤,它只是允许可以过滤数据包或修改数据包的函数挂接到内核网络协议栈中的适当位置。这些函数是可以自定义的。

iptables 是用户层的工具,它提供命令行接口,能够向 Netfilter 中添加规则策略,从而实现报文过滤,修改等功能。Linux 系统中并不止有 iptables 能够生成防火墙规则,其他的工具如 firewalld 等也能实现类似的功能。

iptables 策略是由一组有序的规则建立的,它告诉内核应该如何处理某些类别的数据包。每一个 iptables 规则应用于一个表中的一个链。一个 iptables 链就是一个规则集,这些规则按序与包含某种特征的数据包进行比较匹配。

iptables 服务命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 启动服务
/etc/init.d/iptables start
service iptables start

# 停止服务
/etc/init.d/iptables stop
service iptables stop

# 重启服务
/etc/init.d/iptables restart
service iptables restart

# 保存设置
/etc/init.d/iptables save
service iptables save

iptables 常用命令

1
2
3
4
5
6
7
8
9
iptables -A     # 将一个规则添加到链末尾
iptables -D # 将指定的链中删除规则
iptables -F # 将指定的链中删除所有规则
iptables -I # 将在指定链的指定编号位置插入一个规则
iptables -L # 列出指定链中所有规则
iptables -t # nat -L 列出所有 NAT 链中所有规则
iptables -N # 建立用户定义链
iptables -X # 删除用户定义链
iptables -P # 修改链的默认设置,如将 iptables -P INPUT DROP (将 INPUT 链设置为 DROP)

常见设置参数

  • –dport 指定目标 TCP/IP 端口 如 -dport 80
  • –sport 指定源 TCP/IP 端口 如 -sport 80
  • -p tcp 指定协议为 tcp
  • -p icmp 指定协议为 ICMP
  • -p udp 指定协议为 UDP
  • -j DROP 拒绝
  • -j ACCEPT 允许
  • -j REJECT 拒绝并向发出消息的计算机发一个消息
  • -j LOG 在 / var/log/messages 中登记分组匹配的记录
  • -m mac -mac 绑定 MAC 地址
  • -m limit -limit 1/s 1/m 设置时间策列
  • -s 10.10.0.0 或 10.10.0.0/16 指定源地址或地址段
  • -d 10.10.0.0 或 10.10.0.0/16 指定目标地址或地址段
  • -s ! 10.10.0.0 指定源地址以外的

iptables 配置文件

1
cat /etc/sysconfig/iptables

iptables 表

iptables 默认有 4 个表

  • nat 表(地址转换表)
  • filter 表(数据过滤表)
  • raw 表(状态跟踪表)
  • mangle 表(包标记表)

iptables 链

每个表都有一组内置链,用户还可以添加自定义的链。最重要的内置链是 filter 表中的 INPUT、OUTPUT 和 FORWARD 链。

  • INPUT 链(入站规则)
  • OUTPUT 链(出站规则)
  • FORWARD 链(转发规则)
  • PREROUTING 链(路有前规则)
  • POSTROUTING 链(路由后规则)


配置案例

关闭端口 4444

1
2
3
4
5
6
7
8
iptables -A INPUT -p tcp --dport 4444 -j DROP
iptables -A OUTPUT -p tcp --dport 4444 -j DROP
iptables -L -n # 看一下规则

# 删除INPUT链的第一条规则
iptables -D INPUT 1
# 删除OUTPUT链的第一条规则
iptables -D OUTPUT 1

通过iptables实现ICMP包的过滤

1
2
3
iptables -A INPUT -p icmp -j REJECT
iptables -L -n
iptables -D INPUT 1

放开 4444 端口

1
2
iptables -I INPUT -p tcp --dport 4444 -j ACCEPT
iptables -L -n

只允许 10.211.55.5 访问本机的 4444 端口

1
2
3
4
5
6
7
8
9
iptables -I INPUT -p tcp --dport 4444 -j DROP                   # 首先拒绝所有
iptables -I INPUT -s 10.211.55.5 -p tcp --dport 4444 -j ACCEPT # 配置单一白名单
iptables -L -n

# 注意这里要用 -I ,不要用 -A ,因为这样规则顺序是不一样的,用 -A 拒绝的条件在前

# 然后删除
iptables -D INPUT 1
iptables -D INPUT 1

只允许 10.211.55.5 访问,其他全部拒绝

1
2
3
4
5
6
7
iptables -A INPUT -s 10.211.55.5 -p tcp -j ACCEPT
iptables -A INPUT -p tcp -j REJECT
iptables -L -n

# 顺序很重要!!!!!,先删除第二条,在删除第一条
iptables -D INPUT 2
iptables -D INPUT 1

只允许 1.14.5.14/1.9.1.9 对 8888 的访问

1
2
3
4
iptables -L
iptables -I INPUT -p tcp --dport 8888 -j DROP
iptables -I INPUT -s 1.14.5.14 -p tcp --dport 8888 -j ACCEPT
iptables -I INPUT -s 1.9.1.9 -p tcp --dport 8888 -j ACCEPT

docker 与 firewalld/iptable 的冲突

由于docker在启动容器时,会向iptables注⼊一些端口映射的规则,当使用 firewalld 时会产生冲突

1
2
3
4
5
6
7
8
9
10
iptables -t nat -nL

# 删除对应的 docker 规则
iptables -t nat -D DOCKER 13
# 手动加个转发
iptables -t nat -A DOCKER -d 127.0.0.1 -p tcp -m tcp --dport 19000 -j DNAT --to-destination 192.168.16.2:80

iptables -A INPUT -p tcp --dport 19000 -j DROP
iptables -I INPUT -s 1.14.5.14 -p tcp --dport 19000 -j ACCEPT
iptables -I INPUT -s 1.9.1.9 -p tcp --dport 19000 -j ACCEPT

Source & Reference


firewalld 实验


区域

防火墙各个区说明

  • drop (丢弃)

    任何接收的网络数据包都被丢弃,没有任何回复.仅能有发送出去的网络连接.

  • block (限制)

    任何接收的网络连接都被 IPv4 的 icmp-host-prohibited 信息和 IPv6 的 icmp6-adm-prohibited 信息所拒绝.

  • public (公共)

    在公共区域内使用,不能相信网络内的其他计算机不会对你的计算机造成危害,只能接收经过选取的连接.

  • external (外部)

    特别是为路由器启用了伪装功能的外部网.你不能信任来自网络的其他计算,不能相信它们不会对你的计算机造成危害,只能接收经过选择的连接.

  • dmz (非军事区)

    用于你的非军事区内的电脑,此区域内可公开访问,可以有限地进入你的内部网络,仅仅接收经过选择的连接.

  • work (工作)

    用于工作区.你可以基本相信网络内的其他电脑不会危害你的电脑.仅仅接收经过选择的连接.

  • home (家庭)

    用于家庭网络.你可以基本信任网络内的其他计算机不会危害你的计算机.仅仅接收经过选择的连接.

  • internal (内部)

    用于内部网络.你可以基本上信任网络内的其他计算机不会威胁你的计算机.仅仅接受经过选择的连接.

  • trusted (信任)

    可接受所有的网络连接.适合在故障排除的情况下或者是在你绝对信任的网络上使用.


常用命令

服务管理

1
2
3
systemctl status firewalld	# 查看服务运行状态
systemctl start firewalld # 开启服务
systemctl stop firewalld # 关闭服务

查看

1
2
3
4
5
6
7
8
9
firewall-cmd --state                    # 显示防火墙状态
firewall-cmd --get-zones # 列出当前有几个 zone
firewall-cmd --get-active-zones # 取得当前活动的 zones
firewall-cmd --get-default-zone # 取得默认的 zone
firewall-cmd --get-service # 取得当前支持 service
firewall-cmd --get-service --permanent # 检查下一次重载后将激活的服务

firewall-cmd --zone=public --list-ports # 列出 zone public 端口
firewall-cmd --zone=public --list-all # 列出 zone public 当前设置

配置开放服务/端口

1
2
3
4
5
6
7
firewall-cmd --zone=public --add-service=http       # 增加 zone public 开放http service
firewall-cmd --reload # 重新加载配置

firewall-cmd --zone=public --remove-service=http # 从 zone 中移除 http 服务

firewall-cmd --zone=internal --add-port=443/tcp # 增加 zone internal 开放 443/tcp 协议端口
firewall-cmd --zone=internal --remove-port=443/tcp # 从 zone 中移除 443 端口

设置黑/白名单

1
2
3
4
5
6
7
8
9
10
firewall-cmd --permanent --zone=trusted --add-source=172.28.129.0/24    # 增加 172.28.129.0/24 网段到 zone trusted
firewall-cmd --permanent --zone=trusted --list-sources # 列出 zone truste 的白名单
firewall-cmd --reload
firewall-cmd --get-active-zones

firewall-cmd --permanent --zone=drop --add-source=172.28.13.0/24 # 添加 172.28.13.0/24 到 zone drop
firewall-cmd --reload
firewall-cmd --zone=drop --list-all

firewall-cmd --permanent --zone=drop --remove-source=172.28.13.0/24 # 从zone drop 中删除 172.28.13.0/24
  • 使用命令的时候加上 –permanent 是永久生效的意思,在重启防火墙服务后依然生效.否则,只对重启服务之前有效.
  • 我们执行的命令,结果其实都体现在具体的配置文件中,其实我们可以直接修改对应的配置文件即可.以 public zone 为例,对应的配置文件是 /etc/firewalld/zones/public.xml

自定义区域

你可以随意使用 firewalld 默认提供的这些区域,不过也完全可以创建自己的区域。比如如果希望有一个针对游戏的特别区域,你可以创建一个,然后只有在玩儿游戏的时候切换到该区域。

如果想要创建一个新的空白区域,你可以创建一个名为 game 的新区域,然后重新加载防火墙规则,这样你的新区域就启用了:

1
2
firewall-cmd --new-zone game --permanent
firewall-cmd --reload

配置案例

只允许 1.1.1.1 和 2.2.2.2 访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
systemctl start firewalld
# 配置 IP 白名单
firewall-cmd --permanent --zone=trusted --add-source=1.1.1.1
firewall-cmd --permanent --zone=trusted --add-source=2.2.2.2
# 与此同时,你也要加入你自己的 IP 地址,否则白名单一旦生效,可能会将你阻挡在外而无法连接。
firewall-cmd --reload
# 确认 trusted 区域是否设置正确
firewall-cmd --zone=trusted --list-all

# 因为此时已经设置了 trusted 区域,所以还需要切换默认区域从 public 到 drop,以达到无视所有接入连接的目的
firewall-cmd --set-default-zone=drop

# 将默认网卡 ens33 分配给 drop 区域
firewall-cmd --permanent --zone=drop --change-interface=ens33
firewall-cmd --reload

配置端口白名单

1
2
3
4
5
6
7
8
9
10
11
# 查询端口是否开放
firewall-cmd --query-port=8080/tcp
# 新建永久规则,开放 8080 端口(TCP 协议), 任何 ip 都可以访问
firewall-cmd --permanent --add-port=8080/tcp
# 移除上述规则
firewall-cmd --permanent --remove-port=8080/tcp
# 新建永久规则,批量开放一段端口(TCP 协议)
firewall-cmd --permanent --add-port=9001-9100/tcp

# 添加或者移除规则后重新加载 firewall 后配置才会生效
firewall-cmd --reload

只允许 123.123.123.123/1.2.3.4/1.14.5.14/1.9.1.9 对 8888 的访问

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

firewall-cmd --zone=public --add-port=1-18999/tcp --permanent
firewall-cmd --zone=public --add-port=19001-65535/tcp --permanent

firewall-cmd --zone=public --add-port=1-18999/udp --permanent
firewall-cmd --zone=public --add-port=19001-65535/udp --permanent


firewall-cmd --zone=public --remove-port=19000/tcp --permanent
firewall-cmd --zone=public --remove-port=19000/udp --permanent
firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="123.123.123.123" port port=19000 protocol=tcp accept' --permanent
firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="123.123.123.123" port port=19000 protocol=udp accept' --permanent
firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="1.2.3.4" port port=19000 protocol=tcp accept' --permanent
firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="1.2.3.4" port port=19000 protocol=udp accept' --permanent
firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="1.14.5.14" port port=19000 protocol=tcp accept' --permanent
firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="1.14.5.14" port port=19000 protocol=udp accept' --permanent
firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="1.9.1.9" port port=19000 protocol=tcp accept' --permanent
firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="1.9.1.9" port port=19000 protocol=udp accept' --permanent
firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="0.0.0.0/32" port port=19000 protocol=tcp reject' --permanent
firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address="0.0.0.0/32" port port=19000 protocol=udp reject' --permanent

firewall-cmd --reload
firewall-cmd --zone=public --list-all

firewall-cmd --get-active-zones
firewall-cmd --get-default-zone

firewall-cmd --set-default-zone=public
firewall-cmd --permanent --zone=public --change-interface=ens33

firewall-cmd --reload

docker 与 firewalld/iptable 的冲突

由于docker在启动容器时,会向iptables注⼊一些端口映射的规则,当使用 firewalld 时会产生冲突

1
2
3
4
5
6
7
8
9
10
iptables -t nat -nL

# 删除对应的 docker 规则
iptables -t nat -D DOCKER 13
# 手动加个转发
iptables -t nat -A DOCKER -d 127.0.0.1 -p tcp -m tcp --dport 19000 -j DNAT --to-destination 192.168.16.2:80

iptables -A INPUT -p tcp --dport 19000 -j DROP
iptables -I INPUT -s 1.14.5.14 -p tcp --dport 19000 -j ACCEPT
iptables -I INPUT -s 1.9.1.9 -p tcp --dport 19000 -j ACCEPT

Source & Reference


Linux Iptables & Firewalls
https://msfts.org/2024/10/28/linux-iptables/
作者
Jas0n0ss
发布于
2024年10月29日
许可协议