Linux 防火墙 && iptables

Linux 防火墙 && iptables
[TOC]
防火墙种类
| 对比维度 | 软件防火墙 | 硬件防火墙 |
|---|---|---|
| 定义 | 运行在通用操作系统上的防火墙程序(如 Linux 的 iptables/nftables、firewalld) | 专用设备,内置定制化操作系统和专用芯片(如华为、H3C、Cisco) |
| 资源占用 | ✅ 占用主机 CPU、内存、网络带宽 高流量时可能影响业务性能 | ❌ 不占用服务器资源 独立运行,专芯专用 |
| 性能 | 一般(受限于主机硬件) | 高(有芯片加速,高吞吐) |
| 灵活性 | ✅ 更高!可深度集成到应用、脚本自动化、自定义规则灵活 适合开发/测试/云环境 | ⚠️ 相对固定,依赖厂商功能开放程度 |
| 部署方式 | 安装在服务器、虚拟机、容器中 常见于云服务器(如阿里云的安全组) | 物理/虚拟设备,部署在网络边界 |
| 安全性 | 若主机被攻破,防火墙即失效 | 独立系统,攻击面小 |
| 成本 | 低 | 高(设备采购 + 授权 + 维护) |
| 典型场景 | - 个人电脑防护 - 云服务器基础防护 | - 企业互联网出口 - 数据中心边界防护 |
✅ 所以更准确的说法是: 软件防火墙 = 灵活 + 低成本 + 资源占用 硬件防火墙 = 高性能 + 高可靠 + 独立安全
当公司业务流量高的时候,如果还用软件防火墙,性能跟不上!
如果业务流量没有那么大,可以考虑用软件的防火墙!
面试题:你们公司防火墙是怎么做的??Firewalld 防火墙
核心概念
- firewalld 使用 区域(zone) 管理规则,默认区域通常是
public - 规则分 运行时(临时) 和 永久(—permanent) 两种
- 服务(service)本质是 ==端口+协议== 组合(如 http → tcp/80)
- 匹配优先级: 源IP所属zone > 网卡所属zone > 默认zone
- 富规则(rich rules)优先级高于普通规则
| 操作 | 防火墙状态 | 安全影响 |
|---|---|---|
systemctl stop firewalld | 完全停止,内核无规则 | 所有流量通过 |
firewall-cmd --set-default-zone=trusted | firewalld 仍在运行,但规则为“全放行” | 所有流量通过 |
- 两者对外表现一致:任何端口都可被访问
- 信任所有传入和传出的流量 相当于关闭防火墙(虽然
防火墙服务仍在运行)
1)查看默认的区域[root@R101 ~]# firewall-cmd --get-default-zonepublic# 默认的区域就是public=====================================✅正确做法:只放行必需的服务或端口,例如:firewall-cmd --permanent --add-service=sshfirewall-cmd --permanent --add-service=cockpit# 如果不加 --permanent 则为临时放行指定的服务# 使用场景:你知道对应的服务名即可'当然如果我们只知道端口也是可以的'firewall-cmd --permanent --add-port=22/tcpfirewall-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=cockpitsuccess[root@localhost ~]# firewall-cmd --reloadsuccess[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=sshssh 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 |
| 查看网卡所属 zone | firewall-cmd --get-zone-of-interface=ens160 |
| 删除规则 | --remove-service / --remove-port / --remove-rich-rule |
基本服务放行(HTTP)
目标: 让主机 A 能访问主机 B 的 Web 服务(httpd)
'操作步骤(在 B 上执行):'[root@R39 ~]# yum -y install httpdRocky 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 localhostindexB'本地肯定能拉取到'⚠️本地压根就没有走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 firewalldCreated 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 -I10.0.0.111 172.31.31.164[root@R11 ~]# curl 10.0.0.139curl: (7) Failed to connect to 10.0.0.139 port 80 after 0 ms: Could not connect to server'尝试拉取B的页面....因为防火墙,所以失败!'
解决方法!(1)'临时放行'[root@R39 ~]# hostname -I10.0.0.139 192.168.179.152[root@R39 ~]# firewall-cmd --add-service=httpsuccess# 方法1:在默认区域(public)临时放行 http⚠️当执行firewall-cmd --reload后,临时放行的的规则会失效![root@R11 ~]# curl 10.0.0.139indexB'再次访问,成功访问!'
(2)'永久放行'[root@R39 ~]# firewall-cmd --permanent --add-service=httpsuccess# 方法2:永久放行[root@R39 ~]# firewall-cmd --reloadsuccess✅️永久放行后,重载不失效!# 重载永久配置'永久放行需要重载!'
(3)端口放行'端口也可以永久放行!'[root@R39 ~]# firewall-cmd --add-port=80/tcpsuccess# 方法3:直接放行端口基于源 IP 或网卡分配 zone
在实验之前,我们先清理一下环境![root@R39 ~]# firewall-cmd --permanent --remove-service=httpsuccess'因为我们刚才就是永久放行http,所以这里也得是永久移除,否则不生效!'[root@R39 ~]# firewall-cmd --remove-port=80/tcpsuccess[root@R39 ~]# firewall-cmd --reloadsuccess'别忘记重载一下,使配置生效!'=====================================# A测试验证[root@R11 ~]# curl 10.0.0.139curl: (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=trustedsuccess[root@R11 ~]# curl 10.0.0.139indexB'放行后,成功curl到!!'✅ 禁止某个 IP 或网段访问# 新建一个 zone 并设置默认动作为 drop,然后把该 IP 加入[root@R39 ~]# firewall-cmd --permanent --new-zone=blocklistsuccess[root@R39 ~]# firewall-cmd --permanent --zone=blocklist --set-target=DROPsuccess[root@R39 ~]# firewall-cmd --permanent --zone=blocklist --add-source=10.0.0.0/24success[root@R39 ~]# firewall-cmd --reloadsuccess[root@R11 ~]# curl 10.0.0.139curl: (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/24success[root@R39 ~]# firewall-cmd --permanent --remove-interface=ens160 --zone=trustedsuccess[root@R39 ~]# firewall-cmd --reloadsuccess[root@R39 ~]# firewall-cmd --get-zonesblock 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.139curl: (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=trustedsuccess[root@R11 ~]# curl 10.0.0.139indexB# A再次进行curl,就能拉取到页面了!IPTABLES
名词熟悉

-
容器: 瓶子、罐子~~存放东西
-
表(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 防火墙最核心的一张图
- 用户界面 → 命令行工具 → 内核态
📦 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-legacy | ip_tables | ⚠️ 已淘汰,CentOS 6/7 时代 |
| 路径② 老语法→新内核 | iptables-nft (你敲的还是 iptables) | nf_tables | ✅️ 你现在就是这个 |
| 路径③ 新语法→新内核 | nft | nf_tables | 🆕 未来方向 |
💡 路径② 是过渡方案:内核已经换代了,但语法兼容层让你继续用熟悉的
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
[root@oldboy ~]#iptables --versioniptables v1.8.5 (legacy) "Kylin" --> CentOS 7❌️ 老语法→老内核
[root@Rocky ~]# iptables --versioniptables v1.8.11 (nf_tables) "Rocky"✅️ 老语法→新内核
root@ubuntu ~# iptables --versioniptables v1.8.10 (nf_tables) "Ubuntu"✅️ 老语法→新内核把
firewalld和ufw都关掉以后,这两套发行版的底层iptables用法完全一致,因为操作的是同一个内核框架
❌️ 常见踩坑
坑1:systemctl status iptables 找不到服务
root@ubuntu ~# systemctl status iptablesUnit iptables.service could not be found# ⚠️ iptables 不是 systemd 服务!它是内核模块的用户态工具,命令执行即生效# 规则直接挂在内核 netfilter 上,不依赖任何 systemd 单元运行坑2:ufw 和自己手写的 iptables 规则打架
# ⚠️ ufw 启动时也会往里写规则,和你手写的混在一起很难排查# ✅️ 二选一: 1.关闭 ufw/firewalld && 禁止开机自启 --> 走纯 iptables 路线 2.只用 ufw/firewalld,不手写 iptables坑3:iptables 规则重启丢失
# ⚠️ iptables 命令直接写内核内存,重启就没了# ✅️ 装持久化工具:apt install iptables-persistent -y # Ubuntuyum install iptables-services -y # CentOS📌 终极认知:
- 不管你用 CentOS 还是 Ubuntu
- 关掉上层的
firewalld或ufw之后,iptables命令原样通用- 因为底层的
netfilter只有一个,是 Linux 内核的一部分,和发行版无关
- 关闭ufw防火墙&&禁止开机自启 —> 走纯 iptables 路线
- 装 iptables 持久化工具,完全可行
“坑2”和”坑3”就是在讲这件事
- ufw / firewalld 只是翻译官,关掉之后底层 iptables 命令原样通用
- ==iptables 规则重启丢失==
- → 装持久化工具:iptables-persistent(Ubuntu)或 iptables-services(CentOS)
执行过程

=================================流量通过网络接口层进来,到达网络层; '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:走后门(绕过记录)
🔹 1. PREROUTING(前置路由)✅ 位置:数据包刚进系统时的第一个检查点🎯 作用:还没决定往哪送,先看看要不要改地址(比如 NAT),或者直接丢掉💬 大白话:就像快递刚送到小区门口,保安先看是不是要换地址、要不要拦截
🔹 2. INPUT(输入)✅ 位置:数据包是发给本机的,进入系统后,要交给本地程序之前🎯 作用:判断这个包能不能进我的电脑(比如你有没有权限访问我)💬 大白话:快递确认是寄给我家的,现在问我:“能收吗?”
🔹 3. FORWARD(转发)✅ 位置:数据包不是给本机的,而是要从一个网口转到另一个网口🎯 作用:决定这个包能不能“过境”(转发)。💬 大白话:快递不是给我家的,是寄给隔壁邻居的,我作为中介,要不要帮他传过去?
🔹 4. OUTPUT(输出)✅ 位置:本机自己发出的数据包,在离开之前经过这里🎯 作用:检查我发出去的东西合不合法(比如有没有被禁止)💬 大白话:我自己要寄个快递出门,保安先查一下能不能寄
🔹 5. POSTROUTING(后置路由)✅ 位置:数据包即将离开系统,最后一步🎯 作用:做最后的修改,比如改源IP(NAT)、加标记等💬 大白话:快递要走了,最后贴个“已处理”标签,或者换个名字再发走
'这五个“关卡”就是 iptables 的 五链,配合四张表(Filter、NAT 等)一起工作,控制所有进出网络的数据包!'表与链
============================“表” = 干什么活(功能)比如 Filter 表就是干“放行或拦截”的活,NAT 表就是干“改地址”的活 → 表决定“做什么事”
“链” = 在哪里干活(位置)比如 INPUT 链是在“数据包进本机时”干活,OUTPUT 是在“本机发包时”干活 → 链决定“在哪个关口检查/处理数据包”============================✅表是功能,链是位置(网卡路径上的关键节点)📌 filter表
🌟 filter 表是什么?
它是 iptables 里 **最常用、最核心的一张表 **,相当于你电脑的“防火墙”
🔍 它具体干啥?
- 过滤流量:根据 IP 地址、端口、协议等规则,判断是否允许通过
- 保护主机:防止黑客攻击、非法访问(比如别人想连你的 SSH 的22端口,但你不让)
- 默认使用:你一装 iptables,它就自动用
filter表,不需要额外设置
🔗 它有三个关键“链”(检查点):
| 链名 | 大白话解释 |
|---|---|
| INPUT | 别人发给我的包,能不能让我收到? |
| OUTPUT | 我自己发出去的包,能不能发? |
| FORWARD | 经过我机器转发的包(比如我当路由器),能不能让它穿过? |
✅ 总结一句话:
filter表 = 主机防火墙,负责“拦不拦”数据包,是 iptables 的默认和核心功能
💡 举个例子:你想禁止某个 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:满足条件后的动作,丢弃# 不发送任何响应'后面详解介绍'环境准备及命令
m01 10.0.0.81 172.16.1.81db03 10.0.0.53 172.16.1.53[root@m01 ~]# systemctl stop firewalld[root@m01 ~]# systemctl disable firewalld'仅关闭防火墙和禁止开机自启动 --> 没有卸载'[root@m01 ~]# unameLinux[root@m01 ~]# uname -r4.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_tablesmodprobe iptable_filtermodprobe iptable_natmodprobe ip_conntrackmodprobe ip_conntrack_ftpmodprobe ip_nat_ftpmodprobe ipt_state
'永久'cat >>/etc/rc.local<<EOFmodprobe ip_tablesmodprobe iptable_filtermodprobe iptable_natmodprobe ip_conntrackmodprobe ip_conntrack_ftpmodprobe ip_nat_ftpmodprobe ipt_stateEOF
[root@m01 ~]# lsmod |egrep 'filter|nat|ipt'# 查看模块,我们刚才添加的模块nf_nat_ftp 12770 0nf_conntrack_ftp 18638 1 nf_nat_ftpiptable_nat 12875 0nf_nat_ipv4 14115 1 iptable_natnf_nat 26787 2 nf_nat_ftp,nf_nat_ipv4nf_conntrack 133053 6 nf_nat_ftp,nf_nat,xt_state,nf_nat_ipv4,nf_conntrack_ftp,nf_conntrack_ipv4iptable_filter 12810 0ip_tables 27126 2 iptable_filter,iptable_natlibcrc32c 12644 3 xfs,nf_nat,nf_conntrack[root@m01 ~]# systemctl start iptables[root@m01 ~]# systemctl enable iptablesCreated symlink /etc/systemd/system/basic.target.wants/iptables.service → /usr/lib/systemd/system/iptables.service.# iptables 启动或关闭的命令文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!



