强曰为道

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

第 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
(高优先级 ──────────→ 低优先级)
表名优先级用途内核模块
raw1(最高)连接跟踪之前处理,用于标记不需要跟踪的包iptable_raw
mangle2修改数据包头部(TOS、TTL、MARK 等)iptable_mangle
nat3网络地址转换(SNAT、DNAT、MASQUERADE)iptable_nat
filter4(最低)包过滤(允许/拒绝),这是默认表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 表负责网络地址转换,它只处理每个连接的第一个数据包,后续包会自动按照连接跟踪的记录进行转换:

操作方向说明
SNATPOSTROUTING出站源地址转换(内网→公网)
DNATPREROUTING入站目的地址转换(公网→内网)
MASQUERADEPOSTROUTING出站动态 SNAT(适用于拨号网络)
REDIRECTPREROUTING/OUTPUT本地端口重定向到本机

filter 表

filter 表是默认表,用于决定数据包是否被放行:

用途
INPUT过滤发往本机的数据包
OUTPUT过滤本机发出的数据包
FORWARD过滤经过本机转发的数据包

2.2 五链(Chains)

2.2.1 链的定义

“链"是规则的有序集合。数据包经过某个钩子点时,会遍历该钩子点上所有链中的规则,直到某个规则明确接受(ACCEPT)、丢弃(DROP)或拒绝(REJECT)该包。

2.2.2 五条内置链

链名对应钩子触发条件涉及的表
PREROUTINGPRE_ROUTING数据包进入本机之前raw、mangle、nat
INPUTLOCAL_IN数据包目的是本机进程mangle、filter
FORWARDFORWARD数据包经过本机转发mangle、filter
OUTPUTLOCAL_OUT本机进程发出的数据包raw、mangle、nat、filter
POSTROUTINGPOST_ROUTING数据包离开本机之后mangle、nat

2.2.3 表与链的对应关系(矩阵)

这是 iptables 最重要的知识矩阵:

表 \ 链PREROUTINGINPUTFORWARDOUTPUTPOSTROUTING
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 iprangeIP 范围-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

对比维度DROPREJECT
行为静默丢弃,不回复发送 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)。默认策略只能设置为 ACCEPTDROP,不能设置为 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 iptablesiptables 官方手册
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 命令行的具体用法。