从抽象理论到实际应用,让你真正理解 iptables/netfilter 的工作机制
前言
如果你接触过 Linux 防火墙,一定听说过"四表五链"这个词。但很多人学完还是一头雾水:
- 表和链到底是什么关系?
- 为什么有 4 个表、5 个链?
- 我每天用的 Docker、防火墙、路由器,跟它有什么关系?
这篇文章会用最直白的方式,把四表五链彻底讲清楚。
读完你会明白:
- 四表五链不是抽象理论,是你每天都在用的网络基础设施
- Docker 的
-p端口映射、家里的路由器上网、服务器的防火墙规则,底层都是它在工作
一、核心概念:表是"做什么",链是"何时做"
用一个快递中转站的比喻来建立整体印象:
| 概念 | 比喻 | 说明 |
|---|---|---|
| 链(Chain) | 5 个固定工位 | 每个数据包必须按顺序经过这些工位 |
| 表(Table) | 4 种职能清单 | 每个工位上都贴着这些清单,规定做什么操作 |
| 规则(Rule) | 清单上的具体指令 | 比如"这个地址的包裹拒收" |
一个数据包在 Linux 内核中的旅程,就是依次经过这些工位,被清单上的规则检查和处理。
二、五链:5 个固定检查点
数据包在 Linux 内核中一定会经过这 5 个"工位":
┌─────────────────────────────────────┐
│ 路由判断 │
│ (这个包是发给本机还是转发?) │
└─────────────────────────────────────┘
│
┌───────────────────────┼───────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ INPUT │ │ FORWARD │ │ OUTPUT │
│ (入站) │ │ (转发) │ │ (出站) │
│ 发给本机的包 │ │ 路过本机的包 │ │ 本机发出的包 │
└───────────────┘ └───────────────┘ └───────────────┘
加上路由前后的两个点,一共是 5 个链:
| 链 | 中文 | 检查时机 | 通俗理解 |
|---|---|---|---|
| PREROUTING | 路由前 | 包刚进来,还没决定发给谁 | 包裹刚进处理中心,还没看地址 |
| INPUT | 入站 | 包要交给本机进程 | 包裹是寄给本公司的,送到前台 |
| FORWARD | 转发 | 包要转发给其他机器 | 包裹只是路过,要转给其他分公司 |
| OUTPUT | 出站 | 本机进程发出的包 | 本公司发出的包裹,打包好准备寄出 |
| POSTROUTING | 路由后 | 包要离开网卡之前 | 包裹即将上车发出前的最后检查 |
三、四表:4 种职能清单
每个链上都挂着这 4 张清单,但不同链上生效的清单不同。
| 表 | 中文名 | 职能 | 一句话用途 |
|---|---|---|---|
| raw | 原始 | 连接跟踪 | "这个包别跟踪,提高性能" |
| mangle | 修改 | 报文修改 | "给这个包打个标签,改个 TTL" |
| nat | 地址转换 | 改写 IP 地址 | "把收件人地址改掉(DNAT)" "把发件人地址改掉(SNAT)" |
| filter | 过滤 | 允许/拒绝 | "这个地址的包,拒收(DROP)" |
四、表和链的关系:哪个工位挂哪张清单
这是最核心的一张表,搞懂它就掌握了 80%:
| 表 \ 链 | PREROUTING | INPUT | FORWARD | OUTPUT | POSTROUTING |
|---|---|---|---|---|---|
| raw | ✅ | ❌ | ❌ | ✅ | ❌ |
| mangle | ✅ | ✅ | ✅ | ✅ | ✅ |
| nat | ✅ (DNAT) | ❌ | ❌ | ✅ (DNAT) | ✅ (SNAT) |
| filter | ❌ | ✅ | ✅ | ✅ | ❌ |
说明:
- ✅ = 该表可以在该链上配置规则
- DNAT/SNAT = 该表在该链上主要用于实现这个功能
规律:
filter只管INPUT、FORWARD、OUTPUT(拦不拦)nat的 DNAT 在PREROUTING和OUTPUT,SNAT 在POSTROUTING(改地址)mangle无处不在(改属性)raw只在PREROUTING和OUTPUT(性能优化)
五、数据包完整旅程(三个典型场景)
场景1:访问本机 Web 服务(外部 → 本机)
网卡
│
▼
┌─────────────────────────────────────────┐
│ PREROUTING 链(路由前) │
│ • raw:连接跟踪 │
│ • mangle:修改报文 │
│ • nat:DNAT(端口映射) │
└─────────────────────────────────────────┘
│
▼
路由判断:目标 IP 是本机 → 走 INPUT
│
▼
┌─────────────────────────────────────────┐
│ INPUT 链(入站) │
│ • mangle:修改报文 │
│ • filter:防火墙规则(ACCEPT/DROP) │
└─────────────────────────────────────────┘
│
▼
本机应用程序(如 nginx)
场景2:本机访问外部(本机 → 外部)
本机应用程序(如 curl)
│
▼
┌─────────────────────────────────────────┐
│ OUTPUT 链(出站) │
│ • raw:连接跟踪 │
│ • mangle:修改报文 │
│ • nat:DNAT(可能重定向) │
│ • filter:出站防火墙 │
└─────────────────────────────────────────┘
│
▼
路由判断:决定从哪个网卡发出
│
▼
┌─────────────────────────────────────────┐
│ POSTROUTING 链(路由后) │
│ • mangle:修改报文 │
│ • nat:SNAT(源地址伪装) │
└─────────────────────────────────────────┘
│
▼
网卡 → 发出去
场景3:本机作为路由器(转发包,如 Docker 或家用路由器)
网卡
│
▼
┌─────────────────────────────────────────┐
│ PREROUTING 链 │
│ • nat:DNAT(如 Docker 端口映射) │
└─────────────────────────────────────────┘
│
▼
路由判断:目标 IP 不是本机 → 走 FORWARD
│
▼
┌─────────────────────────────────────────┐
│ FORWARD 链(转发) │
│ • mangle:修改报文 │
│ • filter:转发防火墙规则 │
└─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ POSTROUTING 链 │
│ • nat:SNAT(让内网电脑上网) │
└─────────────────────────────────────────┘
│
▼
网卡 → 发给目标
六、实际应用场景(你每天都在用)
应用1:防火墙禁止 IP 访问
bash
iptables -A INPUT -s 192.168.1.100 -j DROP
背后的原理:
- 链:
INPUT(入站检查点) - 表:
filter(过滤表) - 作用:源 IP 是 192.168.1.100 的包,直接丢弃
应用2:Docker 端口映射 -p 8080:80
bash
docker run -p 8080:80 nginx
Docker 自动添加的规则(简化版):
bash
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80
背后的原理:
- 链:
PREROUTING(路由前) - 表:
nat(地址转换表) - 作用:访问宿主机 8080 端口 → 转发到容器 172.17.0.2 的 80 端口
应用3:让内网电脑上网(SNAT)
bash
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j MASQUERADE
背后的原理:
- 链:
POSTROUTING(包发出前) - 表:
nat(地址转换表) - 作用:内网 IP 段发出的包,源地址伪装成路由器的公网 IP
应用4:禁止本机 curl 访问百度
bash
iptables -A OUTPUT -d 220.181.38.148 -j DROP
背后的原理:
- 链:
OUTPUT(出站检查) - 表:
filter(过滤表) - 作用:本机发往百度 IP 的包,直接丢弃
七、iptables 命令与四表五链的对应
bash
# 语法:iptables -t 表名 操作 链名 规则
# 查看 filter 表的 INPUT 链规则
iptables -t filter -L INPUT
# 查看 nat 表的 PREROUTING 链规则
iptables -t nat -L PREROUTING
# 在 filter 表的 INPUT 链添加规则(禁止某IP)
iptables -t filter -A INPUT -s 192.168.1.100 -j DROP
# 在 nat 表的 PREROUTING 链添加规则(端口转发)
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to 10.0.0.2:80
# 在 nat 表的 POSTROUTING 链添加规则(源地址伪装)
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j MASQUERADE
省略 -t 时的默认行为:
- 如果不指定
-t参数,默认使用filter表 - 所以
iptables -A INPUT -j DROP等价于iptables -t filter -A INPUT -j DROP
八、记忆口诀
PREROUTING 改目标(DNAT),POSTROUTING 改源(SNAT)
INPUT 拦进来,OUTPUT 拦出去,FORWARD 管转发
filter 做过滤,nat 做转换,mangle 改包,raw 提性能
速查表:
| 我想做什么 | 用哪个链 | 用哪个表 |
|---|---|---|
| 禁止外部访问本机端口 | INPUT | filter |
| 端口映射(如 Docker -p) | PREROUTING | nat (DNAT) |
| 让内网电脑上网 | POSTROUTING | nat (SNAT) |
| 禁止本机访问某个网站 | OUTPUT | filter |
| 修改数据包的 TTL | 任意链 | mangle |
| 提高性能,不跟踪连接 | PREROUTING/OUTPUT | raw |
九、常见问题
Q1:为什么有四张表?不能合并吗?
每张表职责不同,分开设计更清晰:
filter只管"拦不拦"nat只管"改地址"mangle只管"改其他属性"raw只管"是否跟踪"
合在一起会让规则混乱不堪。
Q2:为什么数据包要经过这么多链?
每个链对应一个处理阶段,分阶段处理让规则更有条理。就像工厂流水线,每个工位只做一件事。
Q3:Docker 为什么要操作 iptables?
Docker 利用 nat 表的 PREROUTING 链实现端口映射,利用 filter 表的 FORWARD 链控制容器间通信。没有 iptables,Docker 的网络功能就无法工作。
Q4:家用路由器也是 Linux,它用了哪些链?
家用路由器(如 OpenWrt)主要用:
nat表的POSTROUTING:让内网电脑上网filter表的FORWARD:控制内网设备访问权限nat表的PREROUTING:端口映射(如果配置了)
十、总结
| 概念 | 本质 | 一句话 |
|---|---|---|
| 五链 | 5 个固定检查点 | 数据包在 Linux 内核中的必经之路 |
| 四表 | 4 种职能清单 | 规定在每个检查点做什么操作 |
| 规则 | 具体指令 | 配置在表和链上的具体规则 |
四表五链不是抽象的理论,它是 Linux 处理网络数据包的实际框架。 你每天用的 Docker 端口映射、家里的路由器上网、服务器的防火墙规则,底层都是它在工作。
Linux查看系统资源的命令
CPU:vmstat,iostat,mpstat,top ,dstat
内存: vmstat,free ,dstat
磁盘io:vmstat,iostat,top ,dsta
Linux查看服务运行端口的命令
netstat -anpt,lsof -i -P