Linux 防火墙 && iptables

4580 字
23 分钟
Linux 防火墙 && iptables

Linux 防火墙 && iptables#

[TOC]


防火墙种类#

对比维度软件防火墙硬件防火墙
定义运行在通用操作系统上的防火墙程序(如 Linux 的 iptables/nftablesfirewalld专用设备,内置定制化操作系统和专用芯片(如华为、H3C、Cisco)
资源占用✅ 占用主机 CPU、内存、网络带宽 高流量时可能影响业务性能❌ 不占用服务器资源 独立运行,专芯专用
性能一般(受限于主机硬件)高(有芯片加速,高吞吐)
灵活性✅ 更高!可深度集成到应用、脚本自动化、自定义规则灵活 适合开发/测试/云环境⚠️ 相对固定,依赖厂商功能开放程度
部署方式安装在服务器、虚拟机、容器中 常见于云服务器(如阿里云的安全组)物理/虚拟设备,部署在网络边界
安全性若主机被攻破,防火墙即失效独立系统,攻击面小
成本高(设备采购 + 授权 + 维护)
典型场景- 个人电脑防护 - 云服务器基础防护- 企业互联网出口 - 数据中心边界防护
Tip

✅ 所以更准确的说法是: 软件防火墙 = 灵活 + 低成本 + 资源占用 硬件防火墙 = 高性能 + 高可靠 + 独立安全

当公司业务流量高的时候,如果还用软件防火墙,性能跟不上!

如果业务流量没有那么大,可以考虑用软件的防火墙!

Terminal window
面试题:
你们公司防火墙是怎么做的??

Firewalld 防火墙#

核心概念#

  • firewalld 使用 区域(zone) 管理规则,默认区域通常是 public
  • 规则分 运行时(临时)永久(—permanent) 两种
  • 服务(service)本质是 ==端口+协议== 组合(如 http → tcp/80)
  • 匹配优先级: 源IP所属zone > 网卡所属zone > 默认zone
  • 富规则(rich rules)优先级高于普通规则
操作防火墙状态安全影响
systemctl stop firewalld完全停止,内核无规则所有流量通过
firewall-cmd --set-default-zone=trustedfirewalld 仍在运行,但规则为“全放行”所有流量通过
  • 两者对外表现一致:任何端口都可被访问
  • 信任所有传入和传出的流量 相当于关闭防火墙(虽然 防火墙服务 仍在运行)
Terminal window
1)查看默认的区域
[root@R101 ~]# firewall-cmd --get-default-zone
public
# 默认的区域就是public
=====================================
✅正确做法:只放行必需的服务或端口,例如:
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --add-service=cockpit
# 如果不加 --permanent 则为临时放行指定的服务
# 使用场景:你知道对应的服务名即可
'当然如果我们只知道端口也是可以的'
firewall-cmd --permanent --add-port=22/tcp
firewall-cmd --permanent --add-port=9090/tcp
# 别忘了跟tcp,绝大多数网络服务都基于 TCP 协议
# 和上面命令等价
# 使用场景:你运行的是非标准端口的 SSH(如 2222)、或者自定义端口
firewall-cmd --reload
# 需要 reload 才能立即生效
firewall-cmd --list-all
# 列出当前默认区域的所有配置
[root@localhost ~]# systemctl start firewalld.service
[root@localhost ~]# firewall-cmd --permanent --add-service=cockpit
success
[root@localhost ~]# firewall-cmd --reload
success
[root@localhost ~]# firewall-cmd --list-all --zone=public
.....
=====================================
'移除规则!!'
firewall-cmd --remove-port=80/tcp
# 临时移除端口
'临时添加是重载后失效! 临时移除也是重载后失效!'
firewall-cmd --remove-service=http
# 临时移除服务
⚠️想要永久移除端口|服务
--permanent
=====================================
firewall-cmd --info-service <服务名>
# 用于查看预定义服务的详细信息
[root@R101 ~]# firewall-cmd --info-service=ssh
ssh
ports: 22/tcp
protocols:
source-ports:
modules:
destination:
includes:
helpers:
'这里面有默认端口!!!'

常用命令速查#

功能命令
查看默认区域firewall-cmd --get-default-zone
列出所有区域firewall-cmd --get-zones
查看某区域规则firewall-cmd --list-all --zone=public
永久添加服务firewall-cmd --permanent --add-service=http
重载永久配置firewall-cmd --reload
查看网卡所属 zonefirewall-cmd --get-zone-of-interface=ens160
删除规则--remove-service / --remove-port / --remove-rich-rule

基本服务放行(HTTP)#

目标: 让主机 A 能访问主机 B 的 Web 服务(httpd)

Terminal window
'操作步骤(在 B 上执行):'
[root@R39 ~]# yum -y install httpd
Rocky Linux 10 - BaseOS 2.5 kB/s | 4.3 kB 00:01
....
Complete!
[root@R39 ~]# systemctl start httpd
# 安装并启动 httpd
[root@R39 ~]# echo "indexB" > /var/www/html/index.html
[root@R39 ~]# curl localhost
indexB
'本地肯定能拉取到'
⚠️本地压根就没有走firewalld,防火墙!
# 所以你本地拉取的话,直接忽略firewalld
[root@R39 ~]# systemctl status firewalld
firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; preset: enabled)
Active: inactive (dead)
Docs: man:firewalld(1)
[root@R39 ~]# systemctl enable --now firewalld
Created symlink '/etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service' '/usr/lib/systemd/system/firewalld.service'.
Created symlink '/etc/systemd/system/multi-user.target.wants/firewalld.service' '/usr/lib/systemd/system/firewalld.service'.
[root@R39 ~]# systemctl status firewalld
firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; preset: enabled)
Active: active (running) since Mon 2026-03-16 20:28:58 CST; 1s ago
Invocation: 0c32a138515a4b50979a4f8dba8fe7fa
Docs: man:firewalld(1)
Process: 3131 ExecStartPost=/usr/bin/firewall-cmd --state (code=exited, status=0/SUCCESS)
Main PID: 3129 (firewalld)
Tasks: 2 (limit: 22605)
Memory: 31.6M (peak: 55.2M)
CPU: 525ms
CGroup: /system.slice/firewalld.service
└─3129 /usr/bin/python3 -sP /usr/sbin/firewalld --nofork --nopid
Mar 16 20:28:58 R39 systemd[1]: Starting firewalld.service - firewalld - dynamic firewall daemon...
Mar 16 20:28:58 R39 systemd[1]: Started firewalld.service - firewalld - dynamic firewall daemon.
[root@R11 ~]# hostname -I
10.0.0.111 172.31.31.164
[root@R11 ~]# curl 10.0.0.139
curl: (7) Failed to connect to 10.0.0.139 port 80 after 0 ms: Could not connect to server
'尝试拉取B的页面....因为防火墙,所以失败!'
解决方法!
(1)'临时放行'
[root@R39 ~]# hostname -I
10.0.0.139 192.168.179.152
[root@R39 ~]# firewall-cmd --add-service=http
success
# 方法1:在默认区域(public)临时放行 http
⚠️当执行firewall-cmd --reload后,临时放行的的规则会失效!
[root@R11 ~]# curl 10.0.0.139
indexB
'再次访问,成功访问!'
(2)'永久放行'
[root@R39 ~]# firewall-cmd --permanent --add-service=http
success
# 方法2:永久放行
[root@R39 ~]# firewall-cmd --reload
success
✅️永久放行后,重载不失效!
# 重载永久配置
'永久放行需要重载!'
(3)端口放行
'端口也可以永久放行!'
[root@R39 ~]# firewall-cmd --add-port=80/tcp
success
# 方法3:直接放行端口

基于源 IP 或网卡分配 zone#

Terminal window
在实验之前,我们先清理一下环境!
[root@R39 ~]# firewall-cmd --permanent --remove-service=http
success
'因为我们刚才就是永久放行http,所以这里也得是永久移除,否则不生效!'
[root@R39 ~]# firewall-cmd --remove-port=80/tcp
success
[root@R39 ~]# firewall-cmd --reload
success
'别忘记重载一下,使配置生效!'
=====================================
# A测试验证
[root@R11 ~]# curl 10.0.0.139
curl: (7) Failed to connect to 10.0.0.139 port 80 after 0 ms: Could not connect to server
# 此时是访问不到的!
============实验开始!===========
方法1:将 B 的网卡 ens160 移到 trusted 区域
'永久生效'
[root@R39 ~]# firewall-cmd --permanent --change-interface=ens160 --zone=trusted
success
[root@R11 ~]# curl 10.0.0.139
indexB
'放行后,成功curl到!!'
禁止某个 IP 或网段访问
# 新建一个 zone 并设置默认动作为 drop,然后把该 IP 加入
[root@R39 ~]# firewall-cmd --permanent --new-zone=blocklist
success
[root@R39 ~]# firewall-cmd --permanent --zone=blocklist --set-target=DROP
success
[root@R39 ~]# firewall-cmd --permanent --zone=blocklist --add-source=10.0.0.0/24
success
[root@R39 ~]# firewall-cmd --reload
success
[root@R11 ~]# curl 10.0.0.139
curl: (28) Failed to connect to 10.0.0.139 port 80 after 132640 ms: Could not connect to server
# 切换到A访问不了???
我们ens160网卡是放行状态呀!
'即使网卡在 trusted,若源 IP 被 public 拒绝,则仍不通'
⚠️ 注意:源 IP 规则优先于网卡规则
[root@R39 ~]# firewall-cmd --permanent --zone=blocklist --remove-source=10.0.0.0/24
success
[root@R39 ~]# firewall-cmd --permanent --remove-interface=ens160 --zone=trusted
success
[root@R39 ~]# firewall-cmd --reload
success
[root@R39 ~]# firewall-cmd --get-zones
block blocklist dmz drop external home internal nm-shared public trusted work
# 列出所有的区域
[root@R39 ~]# firewall-cmd --list-all --zone=blocklist
# 查看指定区域的配置!
blocklist
target: DROP
ingress-priority: 0
egress-priority: 0
icmp-block-inversion: no
interfaces:
sources:
services:
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
[root@R11 ~]# curl 10.0.0.139
curl: (7) Failed to connect to 10.0.0.139 port 80 after 0 ms: Could not connect to server
# 0s后,访问不到!
=================================
方法2:将 A 的网段加入 trusted 区域
'在B进行操作!'
[root@R39 ~]# firewall-cmd --add-source=10.0.0.0/24 --zone=trusted
success
[root@R11 ~]# curl 10.0.0.139
indexB
# A再次进行curl,就能拉取到页面了!

IPTABLES#

名词熟悉#

image-20260515134707431
image-20260515134707431

  • 容器: 瓶子、罐子~~存放东西

  • 表(table): 存放 的容器

    表里面有很多链!

  • 链(chain): 存放 规则 的容器

  • **规则(**policy): 准许或拒绝规则

Netfilter表(tables)链(chains)规则(Policy)
一栋楼楼里的房子房子里的柜子柜子里衣服,摆放规则
  • Netfilter 是什么?

    是 Linux 内核中用于实现 **包过滤、网络地址转换 **等功能的处理框架

  • 所有网络包 进入/离开 系统时,都会经过这栋“楼”里的检查点

✅就像一栋智能安检大楼,网络包进来后,根据目的地被引导到不同房间(表),再放进对应柜子(链),然后按照柜子里的规则(rules)决定是放行、丢弃还是改造

🔄 两代内核框架#

  • iptables vs nftables

  • 两套完全不同的内核子系统

维度iptables (第一代)nftables (第二代)
内核模块ip_tables, x_tables, ip6_tables 等一堆==nf_tables== 一个统一模块
原生命令iptables, ip6tables, arptables, ebtables==nft== 一条命令搞定所有
规则存储每个表独立存储,重复遍历统一存储,一次遍历
IPv4/IPv6两条命令分开管理一条命令统一管理
性能规则多了线性下降内置集合匹配,快得多

🧱 三层架构#

这是理解 Linux 防火墙最核心的一张图

  • 用户界面 → 命令行工具 → 内核态
Terminal window
📦 CentOS 📦 Ubuntu
─────── ───────
firewalld ufw (上层封装,用户友好)
"都是壳,可关可换"
iptables / nft (命令行工具)
"没有持久化 --> 安装相关工具弥补"
iptables-services / iptables-persistent
netfilter 内核框架 (真正干活的)

📌 一句话总结:

  • 不管什么发行版,内核里跑的防火墙框架就是同一个 netfilter

  • 发行版只是在上面包了不同的”遥控器”

逐层解读

🧱 ① netfilter(内核态) 通俗解释:这是 Linux 内核自带的包过滤引擎,在 TCP/IP 协议栈的必经之路上埋了5个钩子点(hook) 关键认知:它一直在跑,不是某个服务,更不是 systemd 单元

⚙️ ② iptables / nft(命令行工具) 通俗解释:这是你敲命令操作内核 netfilter 的”翻译官” 关键认知:命令走完就生效,规则直接挂在内核上

  • ⚠️ 它是内核功能, 没有服务可言 —> ==装持久化工具==

🚢 ③ firewalld / ufw(上层封装,用户友好) 通俗解释:在 iptables/nft 上再包一层,让你用简单命令管理防火墙 关键认知ufw allow 22 → ufw翻译成复杂iptables规则 → 写入netfilter

  • ✅️ ufw 就是个翻译官,帮你把简单的命令翻译成复杂的 iptables 规则

🔀 三种操作路径#

  • 老语法→老内核 / 老语法→新内核 / 新语法→新内核
路径你敲的命令内核模块现状
路径① 老语法→老内核iptables-legacyip_tables⚠️ 已淘汰,CentOS 6/7 时代
路径② 老语法→新内核iptables-nft (你敲的还是 iptables)nf_tables✅️ 你现在就是这个
路径③ 新语法→新内核nftnf_tables🆕 未来方向

💡 路径② 是过渡方案:内核已经换代了,但语法兼容层让你继续用熟悉的 iptables -A INPUT -p tcp --dport 22 -j ACCEPT

Terminal window
[root@oldboy ~]#iptables --version
iptables v1.8.5 (legacy) "Kylin" --> CentOS 7
❌️ 老语法→老内核
[root@Rocky ~]# iptables --version
iptables v1.8.11 (nf_tables) "Rocky"
✅️ 老语法→新内核
root@ubuntu ~# iptables --version
iptables v1.8.10 (nf_tables) "Ubuntu"
✅️ 老语法→新内核

firewalldufw 都关掉以后,这两套发行版的底层 iptables 用法完全一致,因为操作的是同一个内核框架


❌️ 常见踩坑#

坑1:systemctl status iptables 找不到服务

Terminal window
root@ubuntu ~# systemctl status iptables
Unit iptables.service could not be found
# ⚠️ iptables 不是 systemd 服务!它是内核模块的用户态工具,命令执行即生效
# 规则直接挂在内核 netfilter 上,不依赖任何 systemd 单元运行

坑2:ufw 和自己手写的 iptables 规则打架

Terminal window
# ⚠️ ufw 启动时也会往里写规则,和你手写的混在一起很难排查
# ✅️ 二选一:
1.关闭 ufw/firewalld && 禁止开机自启 --> 走纯 iptables 路线
2.只用 ufw/firewalld,不手写 iptables

坑3:iptables 规则重启丢失

Terminal window
# ⚠️ iptables 命令直接写内核内存,重启就没了
# ✅️ 装持久化工具:
apt install iptables-persistent -y # Ubuntu
yum install iptables-services -y # CentOS

📌 终极认知:

  • 不管你用 CentOS 还是 Ubuntu
    • 关掉上层的 firewalldufw 之后,iptables 命令原样通用
  • 因为底层的 netfilter 只有一个,是 Linux 内核的一部分,和发行版无关
  • 关闭ufw防火墙&&禁止开机自启 —> 走纯 iptables 路线
    • 装 iptables 持久化工具,完全可行

“坑2”和”坑3”就是在讲这件事

  • ufw / firewalld 只是翻译官,关掉之后底层 iptables 命令原样通用
  • ==iptables 规则重启丢失==
    • → 装持久化工具:iptables-persistent(Ubuntu)或 iptables-services(CentOS)

执行过程#

image-20210622185322871-1773621359692-5
image-20210622185322871-1773621359692-5

Terminal window
=================================
流量通过网络接口层进来,到达网络层;
'NetFilter把网络包抓过来,进行规则限制并分析'
通过特定“钩子”(hook points)把数据包钩过来,勾到 Netfilter
# 钩过来之后就可以做相应的限制了!
'触发对应表中的链,按规则逐条匹配并执行动作'
=================================
1.Filter 表(过滤表)
👉 最常用!专门用来决定让不让数据包通过,比如设规则“禁止某个IP访问我”,就在这张表里设置;
'相当于小区门口的保安,看谁能不能进'
2.NAT 表(地址转换表)
👉 用来改 IP 地址的。比如你家路由器把内网(192.168.x.x)的请求“伪装”成公网 IP 出去,回来再转回给你的电脑,就是它干的
'相当于快递代收点,帮你转交包裹还改个标签'
========================
3.Mangle 表(修改表)
👉 比较高级,用来改数据包的头部信息,比如改 TTL(生存时间)、打标记等。一般用得少,除非你要做流量控制或特殊路由
'就像给信封上贴个“加急”标签'
4.Raw 表(原始表)
👉 用来跳过连接跟踪(conntrack)。有些高速或特殊流量不想被系统“记住”是不是同一个连接,就在这里提前处理
'相当于走 VIP 通道,不登记、直接过'
😄总结:
Filter:拦人(放行/拒绝)
NAT:换马甲(改 IP)
Mangle:贴标签(改包内容)
Raw:走后门(绕过记录)

image-20210621200927495-1773621414888-11
image-20210621200927495-1773621414888-11

Terminal window
🔹 1. PREROUTING(前置路由)
位置:数据包刚进系统时的第一个检查点
🎯 作用:还没决定往哪送,先看看要不要改地址(比如 NAT),或者直接丢掉
💬 大白话:就像快递刚送到小区门口,保安先看是不是要换地址、要不要拦截
🔹 2. INPUT(输入)
位置:数据包是发给本机的,进入系统后,要交给本地程序之前
🎯 作用:判断这个包能不能进我的电脑(比如你有没有权限访问我)
💬 大白话:快递确认是寄给我家的,现在问我:“能收吗?”
🔹 3. FORWARD(转发)
位置:数据包不是给本机的,而是要从一个网口转到另一个网口
🎯 作用:决定这个包能不能“过境”(转发)。
💬 大白话:快递不是给我家的,是寄给隔壁邻居的,我作为中介,要不要帮他传过去?
🔹 4. OUTPUT(输出)
位置:本机自己发出的数据包,在离开之前经过这里
🎯 作用:检查我发出去的东西合不合法(比如有没有被禁止)
💬 大白话:我自己要寄个快递出门,保安先查一下能不能寄
🔹 5. POSTROUTING(后置路由)
位置:数据包即将离开系统,最后一步
🎯 作用:做最后的修改,比如改源IP(NAT)、加标记等
💬 大白话:快递要走了,最后贴个“已处理”标签,或者换个名字再发走
'这五个“关卡”就是 iptables 的 五链,配合四张表(Filter、NAT 等)一起工作,控制所有进出网络的数据包!'

表与链#

Terminal window
============================
“表” = 干什么活(功能)
比如 Filter 表就是干“放行或拦截”的活,NAT 表就是干“改地址”的活
表决定“做什么事”
“链” = 在哪里干活(位置)
比如 INPUT 链是在“数据包进本机时”干活,OUTPUT 是在“本机发包时”干活
链决定“在哪个关口检查/处理数据包”
============================
✅表是功能,链是位置(网卡路径上的关键节点)

📌 filter表#

🌟 filter 表是什么?

它是 iptables 里 **最常用、最核心的一张表 **,相当于你电脑的“防火墙

🔍 它具体干啥?

  • 过滤流量:根据 IP 地址、端口、协议等规则,判断是否允许通过
  • 保护主机:防止黑客攻击、非法访问(比如别人想连你的 SSH 的22端口,但你不让)
  • 默认使用:你一装 iptables,它就自动用 filter 表,不需要额外设置

🔗 它有三个关键“链”(检查点):

链名大白话解释
INPUT别人发给我的包,能不能让我收到?
OUTPUT我自己发出去的包,能不能发?
FORWARD经过我机器转发的包(比如我当路由器),能不能让它穿过?

✅ 总结一句话:

filter 表 = 主机防火墙,负责“拦不拦”数据包,是 iptables 的默认和核心功能

Terminal window
💡 举个例子:
你想禁止某个 IP 访问你的服务器,就写一条规则:
iptables -A INPUT -s 1.1.1.1 -j DROP
意思就是:
'在 INPUT 链(进来的包),如果来源是 1.1.1.1,就直接丢掉'
============================
# 这里操控的是filter表,默认-t指定了它,可省略
-t:指定表,不指定默认是filter表
-A:append追加,加入链的末尾
# -I:插入到链的开头
-s:--source,源ip
-j:满足条件后的动作,丢弃
# 不发送任何响应
'后面详解介绍'

环境准备及命令#

Terminal window
m01 10.0.0.81 172.16.1.81
db03 10.0.0.53 172.16.1.53
Terminal window
[root@m01 ~]# systemctl stop firewalld
[root@m01 ~]# systemctl disable firewalld
'仅关闭防火墙和禁止开机自启动 --> 没有卸载'
[root@m01 ~]# uname
Linux
[root@m01 ~]# uname -r
4.19.90-52.22.v2207.ky10.x86_64
# 内核版本
[root@m01 ~]# yum install -y iptables-services
.....
Package iptables-1.8.5-2.ky10.x86_64 is already installed.
Dependencies resolved.
Nothing to do.
Complete!
[root@m01 ~]# rpm -ql iptables
/etc/ethertypes
/etc/sysconfig/ip6tables
/etc/sysconfig/ip6tables-config
/etc/sysconfig/iptables
# 防火墙的配置文件
/etc/sysconfig/iptables-config
/usr/lib/systemd/system/iptables.service
# 防火墙服务配置文件(命令)
'临时'
# 防火墙相关模块 加载到内核中
modprobe ip_tables
modprobe iptable_filter
modprobe iptable_nat
modprobe ip_conntrack
modprobe ip_conntrack_ftp
modprobe ip_nat_ftp
modprobe ipt_state
'永久'
cat >>/etc/rc.local<<EOF
modprobe ip_tables
modprobe iptable_filter
modprobe iptable_nat
modprobe ip_conntrack
modprobe ip_conntrack_ftp
modprobe ip_nat_ftp
modprobe ipt_state
EOF
[root@m01 ~]# lsmod |egrep 'filter|nat|ipt'
# 查看模块,我们刚才添加的模块
nf_nat_ftp 12770 0
nf_conntrack_ftp 18638 1 nf_nat_ftp
iptable_nat 12875 0
nf_nat_ipv4 14115 1 iptable_nat
nf_nat 26787 2 nf_nat_ftp,nf_nat_ipv4
nf_conntrack 133053 6 nf_nat_ftp,nf_nat,xt_state,nf_nat_ipv4,nf_conntrack_ftp,nf_conntrack_ipv4
iptable_filter 12810 0
ip_tables 27126 2 iptable_filter,iptable_nat
libcrc32c 12644 3 xfs,nf_nat,nf_conntrack
[root@m01 ~]# systemctl start iptables
[root@m01 ~]# systemctl enable iptables
Created symlink /etc/systemd/system/basic.target.wants/iptables.service /usr/lib/systemd/system/iptables.service.
# iptables 启动或关闭的命令

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Linux 防火墙 && iptables
https://www.kpyun.fun/posts/basics/extension/extension13/
作者
久棹
发布于
2025-10-05
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
久棹
只要胆子大,天天寒暑假!
公告
欢迎来到久棹的技术小站!本站专注 Linux 运维学习笔记分享,如有问题欢迎交流探讨 🎉
分类
标签
站点统计
文章
98
分类
11
标签
203
总字数
244,453
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录