在 Linux 网络栈(特别是 netfilter/iptables 框架)中,链 (Chain) 是数据包在内核中流动时经过的检查点列表。
你可以把“链”想象成机场安检的排队通道。数据包(旅客)必须按照规定的路线,依次通过这些通道。在每个通道里,内核会拿着规则列表(Rule List)逐一核对:

    “这个包是发给我的吗?”
    “这个包的端口是 53 吗?”
    “这个包来自受信任的 IP 吗?”

如果匹配成功,就执行动作(放行、丢弃、修改、重定向);如果这条链里的所有规则都没匹配上,就执行该链的默认策略 (Policy)(通常是 ACCEPT 放行或 DROP 丢弃)。
. 五大核心链 (The 5 Built-in Chains)
Linux 默认定义了五条标准链,分别处理不同阶段的数据包:
| 链名称 | 英文含义 | 作用时机 | 典型用途 |
| :--- | :--- | :--- | : |
| PREROUTING | 路由前 | 数据包刚进入网卡,内核决定“这个包要去哪”之前。 | DNAT (目标地址转换)、端口重定向 (如你的 DNS 劫持)。此时还没决定是发给本机还是转发。 |
| INPUT | 输入 | 数据包的目标地址是本机,准备交给本机进程处理之前。 | 防火墙过滤进入本机的流量 (如允许 SSH, 禁止 Ping)。 |
| FORWARD | 转发 | 数据包的目标地址不是本机,本机只是作为路由器将其转发给其他设备。 | 路由器核心功能,控制局域网访问互联网,或 VLAN 间路由。 |
| OUTPUT | 输出 | 本机进程产生的数据包,准备发送出去之前。 | 控制本机程序能访问哪些外部服务 (如禁止本机访问某些网站)。 |
| POSTROUTING | 路由后 | 数据包即将离开网卡,发送到线路上之前。 | SNAT/Masquerade (源地址转换,即让内网设备上外网)。 |
. 数据包的流向图 (Packet Flow)
理解链的关键在于理解数据包的路径。
场景 A:别人访问你 (入站流量)
text

[外部网络] 
    ⬇️ 进入网卡
[PREROUTING]  <-- 这里做 DNAT (比如把公网 IP:80 转到内网 IP:8080)
    ⬇️ 路由判断 (目标是我吗?)
    ├─> 是 (Target = Local) ──> [INPUT] --> [本机进程]
    └─> 否 (Target = Other) ──> [FORWARD] --> [POSTROUTING] --> [离开网卡]

场景 B:你访问别人 (出站流量)
text

[本机进程]
    ⬇️ 产生数据包
[OUTPUT]
    ⬇️ 路由判断
[POSTROUTING] <-- 这里做 SNAT/Masquerade (隐藏内网 IP)
    ⬇️ 离开网卡
[外部网络]

场景 C:作为路由器转发 (过境流量)
text

[局域网设备] 
    ⬇️ 进入网卡
[PREROUTING] 
    ⬇️ 路由判断 (目标是外网,不是我)
[FORWARD]     <-- 在这里控制谁能上网,谁不能
    ⬇️
[POSTROUTING] <-- 在这里做 IP 伪装 (Masquerade)
    ⬇️ 离开网卡
[互联网]

. 三个主要表 (Tables) 与 链的关系
iptables 有四个主要的表(Table),每个表包含特定的链。你之前的命令用的是 -t nat,这就是指定了 nat 表。
表格
表名 (Table)    功能    包含的链 (Chains)
filter (默认)    过滤 (允许/拒绝)    INPUT, FORWARD, OUTPUT
nat    地址转换 (修改 IP/端口)    PREROUTING, POSTROUTING, OUTPUT
mangle    修改报文头 (修改 TOS, TTL, 标记)    所有 5 条链
raw    连接追踪豁免 (高性能,不跟踪状态)    PREROUTING, OUTPUT
注意:nat 表里没有 FORWARD 链,因为转发时的地址转换通常在 PREROUTING (入向转换) 和 POSTROUTING (出向转换) 完成。
. 结合你之前的 DNS 重命中命令分析
回顾你的命令:
bash

iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 53

    -t nat: 操作 nat 表(专门用于地址转换)。
    -A PREROUTING: 追加规则到 PREROUTING 链。
        时机:数据包刚从 LAN 口进来,内核还没决定它是发给路由器自己,还是要转发出去。
        目的:在这个阶段拦截所有去往外网 DNS (如 8.8.8.8) 的包。
    -j REDIRECT: 动作是重定向。
        这会自动将数据包的 目标 IP 修改为 本机 IP (127.0.0.1 或 主接口 IP)。
        将 目标端口 修改为 53。
    后续流程:
        因为目标 IP 变成了本机,路由判断会将该包导向 INPUT 链。
        关键点:如果 filter 表的 INPUT 链 没有允许 UDP 53 端口,包会在 INPUT 链被丢弃,导致 DNS 解析失败。

. 自定义链 (User-defined Chains)
除了上述内置链,你还可以创建自己的链,用于模块化化管理规则。

    创建:iptables -N MY_WEB_RULES
    跳转:在内置链中跳转到自定义链:
    bash

    # 如果协议是 TCP 且端口是 80,跳到我定义的链里去详细检查
    iptables -A INPUT -p tcp --dport 80 -j MY_WEB_RULES

    优势:规则清晰,便于批量删除或复用。

总结

    链 (Chain) 是数据包必经的检查站序列。
    PREROUTING 是最早的检查站,适合做重定向(如你的 DNS 劫持)。
    INPUT 是保护本机的最后一道防线。
    FORWARD 是路由器的核心,控制过境流量。
    POSTROUTING 是离开前的最后一站,适合做源地址伪装 (SNAT)。

理解数据包在哪个时间点经过哪条链,是编写正确 iptables 规则的核心。

表 (Table) = 功能模块 (过滤、改地址、改包头、免追踪)。 链 (Chain) = 时间钩子 (刚进来、路由前、路由后、发出去)。 规则匹配 = 只有当 表 支持该 链 时,规则才能生效。

 :

🏭 类比:数据包加工厂

想象数据包是一个集装箱货物,Linux 内核是一个大型物流港口

  1. 表 (Table) = 功能部门 (Function Modules)

    • Raw 部:负责“免检通道”,给特定货物贴标签,跳过后续繁琐检查。
    • Mangle 部:负责“包装修改”,改改货物上的标签(TTL、TOS),或者贴上内部流转的记号(MARK)。
    • Nat 部:负责“地址重写”,把发货人地址改成港口的(SNAT),或者把收货地址改成仓库内部的(DNAT)。
    • Filter 部:负责“安保稽查”,拿着黑名单/白名单决定是放行还是销毁
  2. 链 (Chain) = 流水线工位 (Time Hooks)

    • PREROUTING刚卸货。货物刚下船,还没分清楚是留给港口自己用,还是要转运去别处。(此时只能由 Raw, Mangle, Nat 部门介入)
    • INPUT入库前。确认货物是留给港口自己的,在送入仓库前的最后一道安检。(此时由 Mangle, Filter 部门介入)
    • FORWARD转运中。货物不是港口的,只是路过,要装上另一艘船。(此时由 Mangle, Filter 部门介入)
    • OUTPUT发货前。港口自己生产的货物,准备装船发走。(此时由 Raw, Mangle, Nat, Filter 部门介入)
    • POSTROUTING离港前。货物已经确定要上哪艘船了,在真正离开港口大门前的最后处理。(此时由 Mangle, Nat 部门介入)
  3. 规则匹配 = 部门权限 (Validity)

    • 场景:你想在“刚卸货 (PREROUTING)”的时候,让“安保稽查部 (Filter)”去销毁一个包裹。
    • 结果无效!
    • 原因:安保部 (Filter Table) 的办公地点不在卸货区 (PREROUTING Chain)。他们只在“入库前 (INPUT)”和“转运中 (FORWARD)”有工位。
    • 解决:你必须让“地址重写部 (Nat Table)”在卸货区先改地址,或者等货物流转到“转运中 (FORWARD)”时,再由安保部拦截。

💡 这个模型如何帮你解决实际问题?

当你写出一条命令不生效时,用你的这三句话自查:

案例 1:我想做端口映射(外网访问内网 Web),写了 filter 表的 FORWARD 规则,但不起作用。

  • 自查
    • 功能:我要改地址 (DNAT) -> 应该找 Nat 表
    • 时间:包刚进来,还没路由 -> 应该找 PREROUTING 链
    • 错误点:你可能在 filter 表里写了规则,或者在 nat 表里选了 FORWARD 链。
    • 修正iptables -t nat -A PREROUTING ... (Nat 表 + PREROUTING 链 = ✅ 有效)

案例 2:我想禁止内网访问外网,写了 nat 表的 PREROUTING 规则 DROP 包。

  • 自查
    • 功能:我要过滤/丢弃 -> 应该找 Filter 表
    • 时间:包要转发出去 -> 应该找 FORWARD 链
    • 错误点:nat 表主要负责改地址,虽然理论上可以在 mangle 表 drop,但标准做法是用 filter 表。而且 nat 表没有 FORWARD 链!
    • 修正iptables -A FORWARD -s 192.168.1.0/24 -j DROP (默认 filter 表 + FORWARD 链 = ✅ 有效)

案例 3:我想让本机发出的 DNS 请求不被追踪,写了 filter 表的 OUTPUT 规则 NOTRACK。

  • 自查
    • 功能:免追踪 -> 必须找 Raw 表
    • 时间:本机发出 -> OUTPUT 链
    • 错误点:filter 表没有 NOTRACK 功能,且 raw 表才是在连接追踪之前工作的。
    • 修正iptables -t raw -A OUTPUT -p udp --dport 53 -j NOTRACK (Raw 表 + OUTPUT 链 = ✅ 有效)

 保持这个“功能 x 时间”的矩阵思维,任何复杂的 iptables 问题都能迎刃而解!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐