iptables 完全指南 / 第 02 章:核心概念——四表五链
第 02 章:核心概念——四表五链
本章目标:彻底理解 iptables 的四表(raw、mangle、nat、filter)五链(PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING)架构,掌握规则的匹配逻辑和数据包的完整处理流程。
2.1 四表(Tables)
iptables 的"表"是具有相同功能目标的规则集合。四张表按固定的优先级顺序排列:
2.1.1 表的优先级顺序
raw → mangle → nat → filter
1 2 3 4
(高优先级 ──────────→ 低优先级)
| 表名 | 优先级 | 用途 | 内核模块 |
|---|---|---|---|
raw | 1(最高) | 连接跟踪之前处理,用于标记不需要跟踪的包 | iptable_raw |
mangle | 2 | 修改数据包头部(TOS、TTL、MARK 等) | iptable_mangle |
nat | 3 | 网络地址转换(SNAT、DNAT、MASQUERADE) | iptable_nat |
filter | 4(最低) | 包过滤(允许/拒绝),这是默认表 | iptable_filter |
2.1.2 各表的详细说明
raw 表
raw 表是优先级最高的表,它在连接跟踪(conntrack)之前处理数据包。主要用途是标记不需要进行连接跟踪的数据包,从而提升性能。
数据包进入
│
▼
┌──────────┐
│ raw 表 │ ← 在这里决定是否跳过连接跟踪
└────┬─────┘
│
▼
┌──────────────┐
│ 连接跟踪 │ ← nf_conntrack 处理
└────┬─────────┘
│
▼
┌──────────────┐
│ mangle → nat │ ← 后续的表处理
│ → filter │
└──────────────┘
mangle 表
mangle 表用于修改数据包的元数据,而不是做过滤或 NAT:
| 操作 | 说明 | 典型用途 |
|---|---|---|
| TOS | 修改服务类型字段 | QoS 流量分类 |
| TTL | 修改生存时间 | 隐藏网络拓扑 |
| MARK | 设置标记值 | 策略路由、tc 流量控制 |
| SECMARK | 安全上下文标记 | SELinux 网络策略 |
| CONNSECMARK | 连接安全标记 | SELinux 连接跟踪 |
nat 表
nat 表负责网络地址转换,它只处理每个连接的第一个数据包,后续包会自动按照连接跟踪的记录进行转换:
| 操作 | 链 | 方向 | 说明 |
|---|---|---|---|
| SNAT | POSTROUTING | 出站 | 源地址转换(内网→公网) |
| DNAT | PREROUTING | 入站 | 目的地址转换(公网→内网) |
| MASQUERADE | POSTROUTING | 出站 | 动态 SNAT(适用于拨号网络) |
| REDIRECT | PREROUTING/OUTPUT | 本地 | 端口重定向到本机 |
filter 表
filter 表是默认表,用于决定数据包是否被放行:
| 链 | 用途 |
|---|---|
| INPUT | 过滤发往本机的数据包 |
| OUTPUT | 过滤本机发出的数据包 |
| FORWARD | 过滤经过本机转发的数据包 |
2.2 五链(Chains)
2.2.1 链的定义
“链"是规则的有序集合。数据包经过某个钩子点时,会遍历该钩子点上所有链中的规则,直到某个规则明确接受(ACCEPT)、丢弃(DROP)或拒绝(REJECT)该包。
2.2.2 五条内置链
| 链名 | 对应钩子 | 触发条件 | 涉及的表 |
|---|---|---|---|
PREROUTING | PRE_ROUTING | 数据包进入本机之前 | raw、mangle、nat |
INPUT | LOCAL_IN | 数据包目的是本机进程 | mangle、filter |
FORWARD | FORWARD | 数据包经过本机转发 | mangle、filter |
OUTPUT | LOCAL_OUT | 本机进程发出的数据包 | raw、mangle、nat、filter |
POSTROUTING | POST_ROUTING | 数据包离开本机之后 | mangle、nat |
2.2.3 表与链的对应关系(矩阵)
这是 iptables 最重要的知识矩阵:
| 表 \ 链 | PREROUTING | INPUT | FORWARD | OUTPUT | POSTROUTING |
|---|---|---|---|---|---|
| raw | ✅ | — | — | ✅ | — |
| mangle | ✅ | ✅ | ✅ | ✅ | ✅ |
| nat | ✅ | — | — | ✅ | ✅ |
| filter | — | ✅ | ✅ | ✅ | — |
记忆技巧:
raw表只有两个链:入口(PREROUTING)和出口(OUTPUT)mangle表五个链都有nat表在路由决策前后都有(PREROUTING 做 DNAT,POSTROUTING 做 SNAT)filter表只在本地处理(INPUT、OUTPUT)和转发(FORWARD)
2.3 规则(Rules)
2.3.1 规则的结构
一条 iptables 规则由两部分组成:
iptables [选项] -匹配条件 -j 动作
───────── ──────
匹配(Match) 目标(Target)
完整结构:
iptables -t 表名 -A 链名 \
-p 协议 \
-s 源地址 \
-d 目的地址 \
--sport 源端口 \
--dport 目的端口 \
-i 入接口 \
-o 出接口 \
-j 目标动作
2.3.2 规则示例解析
iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 22 -j ACCEPT
| 组成部分 | 值 | 说明 |
|---|---|---|
| 表 | filter(默认) | 未指定 -t,使用默认的 filter 表 |
| 链 | INPUT | 处理发往本机的数据包 |
| 操作 | -A | 追加到链末尾 |
| 协议 | -p tcp | 匹配 TCP 协议 |
| 源地址 | -s 192.168.1.0/24 | 来自 192.168.1.0/24 网段 |
| 目的端口 | --dport 22 | 目的端口是 22(SSH) |
| 动作 | -j ACCEPT | 接受该数据包 |
语义:允许来自 192.168.1.0/24 网段的 SSH 连接请求。
2.4 匹配(Matches)
2.4.1 隐式匹配
隐式匹配是基于协议的内置匹配,不需要额外的 -m 参数:
| 参数 | 说明 | 示例 |
|---|---|---|
-p tcp | 匹配 TCP 协议 | -p tcp --dport 80 |
-p udp | 匹配 UDP 协议 | -p udp --dport 53 |
-p icmp | 匹配 ICMP 协议 | -p icmp --icmp-type echo-request |
# 隐式匹配:--dport 依赖 -p tcp
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# ❌ 错误:没有指定协议就使用端口匹配
iptables -A INPUT --dport 80 -j ACCEPT # 报错!
2.4.2 显式匹配
显式匹配需要使用 -m 参数加载扩展模块:
| 模块 | 说明 | 示例 |
|---|---|---|
-m conntrack | 连接跟踪状态 | -m conntrack --ctstate ESTABLISHED |
-m multiport | 多端口匹配 | -m multiport --dports 80,443 |
-m iprange | IP 范围 | -m iprange --src-range 192.168.1.1-192.168.1.100 |
-m limit | 速率限制 | -m limit --limit 10/s |
-m string | 字符串匹配 | -m string --string "malware" --algo bm |
-m time | 时间匹配 | -m time --timestart 08:00 --timestop 18:00 |
-m owner | 进程/用户匹配 | -m owner --uid-owner 1000 |
-m comment | 添加注释 | -m comment --comment "Allow SSH" |
# 显式匹配:加载 conntrack 模块
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 多端口匹配
iptables -A INPUT -p tcp -m multiport --dports 80,443,8080 -j ACCEPT
# 带注释的规则
iptables -A INPUT -p tcp --dport 22 -m comment --comment "Allow SSH access" -j ACCEPT
2.5 动作(Targets)
2.5.1 基本动作
| 动作 | 说明 | 能否继续匹配 |
|---|---|---|
ACCEPT | 接受数据包 | 否 |
DROP | 静默丢弃数据包 | 否 |
REJECT | 拒绝并返回错误消息 | 否 |
RETURN | 返回到调用链继续匹配 | 是 |
QUEUE | 传递给用户态程序处理 | 取决于程序 |
2.5.2 DROP vs REJECT
| 对比维度 | DROP | REJECT |
|---|---|---|
| 行为 | 静默丢弃,不回复 | 发送 ICMP/TCP RST 回复 |
| 安全性 | 更高(不暴露防火墙存在) | 较低(暴露主机存在) |
| 调试 | 困难(对端超时) | 方便(对端立即收到拒绝) |
| 性能 | 更好 | 需构造回复包 |
| 适用场景 | 生产环境外部接口 | 开发/测试环境、内部网络 |
| 对端体验 | 连接超时 | “Connection refused” |
# DROP:外部流量静默丢弃
iptables -A INPUT -s 0.0.0.0/0 -j DROP
# REJECT:内部测试环境,方便调试
iptables -A INPUT -s 10.0.0.0/8 -p tcp --dport 3306 -j REJECT --reject-with tcp-reset
2.5.3 自定义链
自定义链用于规则分组,提高可读性和管理效率:
# 创建自定义链
iptables -N SSH_RULES
# 在自定义链中添加规则
iptables -A SSH_RULES -s 192.168.1.0/24 -j ACCEPT
iptables -A SSH_RULES -s 10.0.0.0/8 -j ACCEPT
iptables -A SSH_RULES -j DROP
# 在主链中调用自定义链
iptables -A INPUT -p tcp --dport 22 -j SSH_RULES
INPUT 链规则遍历:
┌─────────────────────────────────────────────┐
│ 1. -m conntrack --ctstate ESTABLISHED -j ACCEPT │
│ 2. -p tcp --dport 22 -j SSH_RULES │──→ SSH_RULES 链
│ 3. -p tcp --dport 80 -j ACCEPT │ ├── 192.168.1.0/24 → ACCEPT
│ 4. -j DROP │ ├── 10.0.0.0/8 → ACCEPT
│ │ └── 默认 → DROP
└─────────────────────────────────────────────┘
2.6 数据包完整流向
2.6.1 入站数据包(到本机)
网卡接收 → PREROUTING → 路由决策 → INPUT → 本机进程
│ │
▼ ▼
raw 表处理 filter 表处理
mangle 表处理 mangle 表处理
nat 表(DNAT)
处理顺序(按表优先级):
rawPREROUTINGmanglePREROUTINGnatPREROUTING(DNAT)- 路由决策:目的是本机 → INPUT
mangleINPUTfilterINPUT
2.6.2 转发数据包
网卡接收 → PREROUTING → 路由决策 → FORWARD → POSTROUTING → 网卡发出
│ │ │
▼ ▼ ▼
raw 表处理 filter 表处理 nat 表(SNAT)
mangle 表处理 mangle 表处理 mangle 表处理
nat 表(DNAT)
处理顺序:
rawPREROUTINGmanglePREROUTINGnatPREROUTING(DNAT)- 路由决策:需要转发 → FORWARD
mangleFORWARDfilterFORWARDmanglePOSTROUTINGnatPOSTROUTING(SNAT/MASQUERADE)
2.6.3 出站数据包(从本机发出)
本机进程 → OUTPUT → 路由决策 → POSTROUTING → 网卡发出
│ │
▼ ▼
raw 表处理 nat 表(SNAT)
mangle 表处理 mangle 表处理
nat 表(DNAT)
filter 表处理
处理顺序:
rawOUTPUTmangleOUTPUTnatOUTPUT(DNAT)filterOUTPUT- 路由决策
manglePOSTROUTINGnatPOSTROUTING(SNAT/MASQUERADE)
2.7 规则匹配的遍历逻辑
数据包到达某条链
│
▼
┌──────────────────┐
│ 取出第一条规则 │
└───────┬──────────┘
│
▼
┌──────────────────┐ 是 ┌────────────┐
│ 规则匹配? │────────→│ 执行动作 │
└───────┬──────────┘ └──────┬─────┘
│ 否 │
▼ ▼
┌──────────────────┐ ┌──────────────┐
│ 有下一条规则? │ │ ACCEPT/DROP? │
└───────┬──────────┘ │ → 结束遍历 │
│ 是 │ RETURN? │
▼ │ → 返回调用链 │
取出下一条规则 │ 其他? │
│ → 继续遍历 │
└──────────────┘
│ 否
▼
┌──────────────────┐
│ 执行默认策略 │
│ (Policy) │
└──────────────────┘
重要:当所有规则都不匹配时,执行链的默认策略(Policy)。默认策略只能设置为
ACCEPT或DROP,不能设置为REJECT。
2.8 实验:理解规则执行顺序
实验 1:观察表的优先级
# 在 raw 表的 PREROUTING 链添加日志
sudo iptables -t raw -A PREROUTING -p icmp -j LOG --log-prefix "RAW-PREROUTING: "
# 在 mangle 表的 PREROUTING 链添加日志
sudo iptables -t mangle -A PREROUTING -p icmp -j LOG --log-prefix "MANGLE-PREROUTING: "
# 在 nat 表的 PREROUTING 链添加日志
sudo iptables -t nat -A PREROUTING -p icmp -j LOG --log-prefix "NAT-PREROUTING: "
# 在 filter 表的 INPUT 链添加日志
sudo iptables -A INPUT -p icmp -j LOG --log-prefix "FILTER-INPUT: "
# 从另一台机器 ping 本机,然后查看日志
sudo dmesg | grep -E "(RAW|MANGLE|NAT|FILTER)-PREROUTING|FILTER-INPUT"
预期输出顺序:
RAW-PREROUTING: IN=eth0 ...
MANGLE-PREROUTING: IN=eth0 ...
NAT-PREROUTING: IN=eth0 ...
FILTER-INPUT: IN=eth0 ...
实验 2:第一条匹配规则生效
# 清空规则
sudo iptables -F
# 先添加 ACCEPT,再添加 DROP(针对同一条件)
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j DROP
# 测试:curl 本机 80 端口(如果运行了 web 服务)→ 应该能连接
# 因为第一条规则 ACCEPT 已经匹配,第二条 DROP 不会执行
实验 3:调换顺序观察不同结果
# 清空规则
sudo iptables -F
# 先 DROP,再 ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j DROP
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# 测试:curl 本机 80 端口 → 应该被拒绝
# 因为第一条规则 DROP 已经匹配并终止遍历
2.9 常见误区
误区 1:规则越多越安全
事实:规则越多,遍历时间越长,性能越差。应将高频命中的规则放在前面。
# ❌ 性能差:高频规则在后面
iptables -A INPUT -p tcp --dport 8443 -j ACCEPT # 罕见
iptables -A INPUT -p tcp --dport 53 -j ACCEPT # 罕见
iptables -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT # 高频
# ✅ 性能好:高频规则在前面
iptables -A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT # 高频
iptables -A INPUT -p tcp --dport 8443 -j ACCEPT # 罕见
iptables -A INPUT -p tcp --dport 53 -j ACCEPT # 罕见
误区 2:nat 表可以做过滤
事实:nat 表的设计目的不是过滤,而是地址转换。过滤应在 filter 表中完成。
误区 3:-F 就够了
事实:iptables -F 只清空 filter 表的规则,不会清空其他表。完整清空需要:
iptables -F # 清空 filter 表
iptables -t nat -F # 清空 nat 表
iptables -t mangle -F # 清空 mangle 表
iptables -t raw -F # 清空 raw 表
2.10 注意事项
⚠️ 规则顺序至关重要:iptables 采用"首次匹配"策略,第一个匹配的规则就决定了数据包的命运,后续规则不再检查。
⚠️ 自定义链不能设置默认策略:只有五条内置链才能用
-P设置默认策略。
⚠️ nat 表的特殊性:nat 表只处理每个连接的第一个包(新建连接),后续包根据 conntrack 记录自动处理,因此在 nat 表中做状态匹配(ESTABLISHED)是多余的。
2.11 扩展阅读
| 资源 | 说明 |
|---|---|
man iptables | iptables 官方手册 |
man iptables-extensions | 扩展匹配和目标的手册 |
| RFC 3234 - Middlebox | 中间件(防火墙/NAT)标准 |
| 《Understanding Linux Network Internals》 | Christian Benvenuti 著 |
本章小结
| 概念 | 要点 |
|---|---|
| 四表 | raw → mangle → nat → filter(按优先级) |
| 五链 | PREROUTING、INPUT、FORWARD、OUTPUT、POSTROUTING |
| 规则 | 匹配条件 + 目标动作,按顺序遍历 |
| 匹配 | 隐式(协议内置)和显式(-m 模块加载) |
| 动作 | ACCEPT、DROP、REJECT、RETURN |
| 数据包流向 | 入站:PREROUTING→INPUT;转发:PREROUTING→FORWARD→POSTROUTING |
| 首次匹配 | 第一条匹配规则生效,后续规则不再检查 |
下一章:第 03 章:基本语法与操作,将学习 iptables 命令行的具体用法。