强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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)

处理顺序(按表优先级):

  1. raw PREROUTING
  2. mangle PREROUTING
  3. nat PREROUTING(DNAT)
  4. 路由决策:目的是本机 → INPUT
  5. mangle INPUT
  6. filter INPUT

2.6.2 转发数据包

网卡接收 → PREROUTING → 路由决策 → FORWARD → POSTROUTING → 网卡发出
              │                      │            │
              ▼                      ▼            ▼
         raw 表处理              filter 表处理  nat 表(SNAT)
         mangle 表处理           mangle 表处理  mangle 表处理
         nat 表(DNAT)

处理顺序:

  1. raw PREROUTING
  2. mangle PREROUTING
  3. nat PREROUTING(DNAT)
  4. 路由决策:需要转发 → FORWARD
  5. mangle FORWARD
  6. filter FORWARD
  7. mangle POSTROUTING
  8. nat POSTROUTING(SNAT/MASQUERADE)

2.6.3 出站数据包(从本机发出)

本机进程 → OUTPUT → 路由决策 → POSTROUTING → 网卡发出
              │                      │
              ▼                      ▼
         raw 表处理              nat 表(SNAT)
         mangle 表处理           mangle 表处理
         nat 表(DNAT)
         filter 表处理

处理顺序:

  1. raw OUTPUT
  2. mangle OUTPUT
  3. nat OUTPUT(DNAT)
  4. filter OUTPUT
  5. 路由决策
  6. mangle POSTROUTING
  7. nat POSTROUTING(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 命令行的具体用法。