iptables PREROUTING、FORWARD 与 POSTROUTING 详解

This article is extracted from the chat log with AI. Please identify it with caution.

说明:本文由 Codex 根据作者提供的主题、素材与公开资料辅助生成,属于 AI 生成/整理内容,非作者原创。请读者自行甄别并交叉验证。

先说结论#

PREROUTINGFORWARDPOSTROUTING 是 Linux netfilter/iptables 处理数据包时常见的链。

可以先这样记:

PREROUTING:刚进机器,路由决策之前;
FORWARD:不是发给本机,而是要从本机转发出去;
POSTROUTING:即将离开机器,路由决策之后。

一条转发流量大致会经过:

网卡收到包
PREROUTING
路由决策
FORWARD
POSTROUTING
网卡发出包

这三个链常用于理解:

  • Linux 网关。
  • NAT。
  • Docker 端口映射。
  • Kubernetes kube-proxy iptables 模式。
  • Pod 跨节点访问。
  • Service ClusterIP 转发。

表和链#

iptables 里有两个容易混淆的概念:

table:按用途分类的规则集合;
chain:数据包在某个时机经过的规则列表。

常见 table:

table作用
filter过滤流量,决定 ACCEPT / DROP
nat地址转换,做 DNAT / SNAT / MASQUERADE
mangle修改包标记、TTL 等更细节属性
raw连接跟踪前的特殊处理
securitySELinux 等安全标记相关处理

常见 chain:

chain大致时机
PREROUTING包进入后,路由判断前
INPUT目标是本机进程
FORWARD目标不是本机,要转发
OUTPUT本机进程发出的包
POSTROUTING包离开前

不是每张 table 都有所有 chain。

例如:

  • filter 表常见 INPUTFORWARDOUTPUT
  • nat 表常见 PREROUTINGINPUTOUTPUTPOSTROUTING
  • mangle 表覆盖更多链。

三类路径#

理解 iptables 链,先把包分成三类。

访问本机#

例如外部访问本机 22 端口:

外部机器
本机网卡
PREROUTING
路由判断:目标是本机
INPUT
sshd

这类流量重点看:

  • PREROUTING:是否做 DNAT。
  • INPUT:是否允许进入本机进程。

本机发出#

例如本机执行 curl https://example.com

本机进程
OUTPUT
路由判断
POSTROUTING
网卡发出

这类流量重点看:

  • OUTPUT:本机出站规则。
  • POSTROUTING:是否做 SNAT/MASQUERADE。

本机转发#

例如 Linux 主机作为网关,或 Kubernetes Node 转发 Pod 流量:

源机器 / Pod
进入本机网卡
PREROUTING
路由判断:目标不是本机
FORWARD
POSTROUTING
发往下一跳

这类流量重点看:

  • PREROUTING:目标地址是否被改写。
  • FORWARD:内核是否允许转发。
  • POSTROUTING:源地址是否被改写。

PREROUTING#

PREROUTING 的位置很早。

包刚进入机器,还没有做最终路由决策时,就会经过它。

典型用途是 DNAT:

把目标地址 / 目标端口改掉。

例如把访问本机公网 80 端口的流量转到内网某台机器:

iptables -t nat -A PREROUTING \
  -p tcp --dport 80 \
  -j DNAT --to-destination 10.0.0.10:8080

含义是:

如果进入本机的 TCP 包目标端口是 80;
在路由决策前,把目标改成 10.0.0.10:8080。

为什么要在路由前改?

因为目标地址变了以后,内核才能根据新的目标地址重新决定这个包应该走哪条路。

在 Kubernetes 里,Service ClusterIP 的 DNAT 也常发生在类似路径上:包访问虚拟 IP,规则把目标改成某个后端 Pod IP。

FORWARD#

FORWARD 处理的是“经过本机转发”的包。

判断标准是:

这个包不是发给本机进程;
也不是本机进程发出的;
而是从一个网络接口进入,再从另一个接口出去。

例如:

Pod A -> Node -> Pod B
客户端 -> Linux 网关 -> 外部网络
容器 -> 宿主机 -> 外部网络

这类流量会经过 FORWARD

filter 表中的 FORWARD 常用于决定能不能转发:

iptables -A FORWARD -s 10.244.0.0/16 -j ACCEPT
iptables -A FORWARD -j DROP

如果 Linux 没开启转发,即使 iptables 放行也不能正常转发。

检查:

sysctl net.ipv4.ip_forward

临时开启:

sysctl -w net.ipv4.ip_forward=1

持久化通常写入 /etc/sysctl.conf/etc/sysctl.d/*.conf

POSTROUTING#

POSTROUTING 的位置很晚。

路由已经决定,包即将离开机器时,会经过它。

典型用途是 SNAT 或 MASQUERADE:

把源地址改掉。

例如让内网机器通过网关访问外网:

iptables -t nat -A POSTROUTING \
  -s 10.0.0.0/24 \
  -o eth0 \
  -j MASQUERADE

含义是:

来自 10.0.0.0/24 的流量;
如果从 eth0 出去;
离开前把源地址伪装成 eth0 的地址。

为什么要在路由后改?

因为内核已经知道这个包要从哪个出口出去,这时才能根据出口地址做合适的源地址转换。

在 Kubernetes 里,Pod 访问集群外部地址时,如果外部网络不知道 Pod CIDR 的回程路由,节点可能需要对 Pod 源地址做 SNAT/MASQUERADE。

DNAT 和 SNAT#

PREROUTING 常见 DNAT。

改目标地址:你本来要去 A,现在改去 B。

POSTROUTING 常见 SNAT。

改源地址:你本来来自 A,现在看起来来自 B。

可以这样记:

NAT 类型常见链修改内容典型场景
DNATPREROUTING目标地址/端口端口转发、Service 转后端
SNATPOSTROUTING源地址/端口内网出公网、Pod 出集群
MASQUERADEPOSTROUTING动态 SNAT出口 IP 可能变化的场景

NAT 通常只在连接创建时决定转换关系,后续数据包依赖 conntrack 记住映射。

和路由表的关系#

iptables 和路由表不是一回事。

路由表回答:

这个包应该从哪个接口出去,下一跳是谁?

iptables 回答:

这个包是否允许?
是否要修改源地址或目标地址?
是否要打标记?

一个转发包的关键顺序是:

PREROUTING
路由决策
FORWARD
POSTROUTING

这也是为什么:

  • 目标地址转换通常在路由前做。
  • 源地址转换通常在路由后做。
  • FORWARD 只处理被路由转发的包。

Kubernetes 中的典型场景#

iptables 在 Kubernetes 中最常见于以下位置:

  • kube-proxy 的 iptables 数据面。
  • Service ClusterIP 或 NodePort 到 Endpoint Pod IP 的 DNAT。
  • Pod 访问集群外部网络时的 SNAT / MASQUERADE。
  • CNI 安装的转发、隔离和 NAT 规则。

先确认集群实际使用的数据面。iptables、IPVS、nftables 和 eBPF 都可能承担 Service 转发职责;VXLAN、IPIP、WireGuard 等 CNI 封装也会改变跨节点路径。KUBE-SERVICESKUBE-SVC-*KUBE-SEP-* 只是 kube-proxy iptables 模式中常见的链名,不能把它们当作每个集群都必然存在的前提。

Service 流量#

以 kube-proxy 的 iptables 模式为例,访问 ClusterIP 或 NodePort 的报文会匹配 Service 规则,选择一个 Endpoint,并把目标改写为该 Endpoint 的 PodIP:targetPort。改写之后,内核再按 Pod IP 选择路由:目标 Pod 在本机时交给本机 veth;在远端时则交给 CNI 配置的路由或隧道。

客户端或 Pod
nat/PREROUTING(本机进程发起时通常是 nat/OUTPUT)
Service 规则选择 Endpoint,并 DNAT 到 PodIP:targetPort
基于 PodIP 的路由、FORWARD 与必要的封装
目标 Pod

常见 Kubernetes 路径对照#

场景典型流转路径优先排查
Pod 访问 ClusterIPPod veth → PREROUTING → Service 规则与 DNAT → 路由到后端 PodService、EndpointSlice、kube-proxy 或 eBPF 数据面
节点本机进程访问 ClusterIPOUTPUT → Service 规则与 DNAT → POSTROUTINGnat/OUTPUT,而不是 PREROUTING
外部客户端访问 NodePorteth0 → PREROUTING → Service 规则与 DNAT → FORWARD → PodNodePort 规则、EndpointSlice、FORWARD、回程 SNAT 策略
Pod 访问互联网Pod veth → PREROUTING → FORWARD → POSTROUTING → eth0Pod CIDR 路由、FORWARD、MASQUERADE

这些都是便于理解的典型路径。Pod 是否与源端同节点、CNI 是否使用隧道、externalTrafficPolicy、kube-proxy 模式和节点防火墙规则都会影响实际细节。

Pod 出网时,CNI 或节点网络配置通常会在 POSTROUTING 做 MASQUERADE,使外部网络只需把响应返回给 Node IP。不要把“Pod 出网一定由 kube-proxy 做 SNAT”当作通用结论;CNI、Pod CIDR 的路由方式、Service 配置和节点网络策略都会参与决定。

常用查看命令#

查看 filter 表:

iptables -L -n -v
iptables -S

查看 nat 表:

iptables -t nat -L -n -v
iptables -t nat -S

保存完整规则:

iptables-save
iptables-save -t nat

查看路由:

ip route
ip rule

查看连接跟踪:

conntrack -L
conntrack -L -p tcp

抓包:

tcpdump -ni any host 10.0.0.10
tcpdump -ni eth0 tcp port 80

排查时建议同时看:

iptables 规则
路由表
sysctl 转发开关
conntrack
tcpdump

只看其中一个,很容易误判。

Kubernetes Service 排查顺序#

Service 请求异常时,先确认 API 对象和节点数据面是否都符合预期,再逐段追包:

# 1. Service 是否有可用后端
kubectl get svc -A
kubectl get endpointslice -A

# 2. 节点上由谁实现 Service 数据面
kubectl -n kube-system get ds kube-proxy
kubectl -n kube-system logs ds/kube-proxy

# 3. 确认 DNAT 后到目标 Pod IP 的路由和转发条件
ip route get <pod-ip>
sysctl net.ipv4.ip_forward
iptables -t nat -L PREROUTING -n -v --line-numbers
iptables -L FORWARD -n -v --line-numbers
iptables -t nat -L POSTROUTING -n -v --line-numbers

若节点使用 iptables-nft 兼容层,iptables 命令仍可能可用,但底层规则由 nftables 管理;必要时同时检查:

nft list ruleset
conntrack -L
tcpdump -ni any host <pod-ip>

检查应分别在源节点和目标节点进行。看到 Service 已 DNAT 到 Pod IP 只能证明前半段规则命中;后续的路由、FORWARD、CNI 封装、NetworkPolicy 与回程 NAT 仍可能使请求失败。

常见误区#

PREROUTING 只影响转发流量#

不准确。

进入本机的包也会先经过 PREROUTING,然后再由路由判断是进入 INPUT 还是 FORWARD。

FORWARD 会处理本机访问外部的包#

不会。

本机进程发出的包走 OUTPUT 和 POSTROUTING,不走 FORWARD。

POSTROUTING 只能做 SNAT#

POSTROUTING 常用于 SNAT/MASQUERADE,但它属于链的位置,不等于只能做一个动作。不同 table 和 target 能做的事由内核模块和 iptables 扩展决定。

iptables 负责选路#

iptables 可以修改包、过滤包、打标记,但真正决定下一跳的是路由系统。

有些高级场景会通过 mark 配合 policy routing,但那仍然是 iptables 和路由表协作。

看到 Kubernetes Service 的 DNAT 后就说明链路已通#

不成立。DNAT 只改写目标地址;后续仍可能因为 Pod 路由错误、FORWARD 拦截、CNI 封装、网络策略,或回程 SNAT 配置不当而失败。

所有 Kubernetes 集群都有 KUBE-* 链#

不成立。先确认 kube-proxy 的模式以及 CNI 类型。iptables、IPVS、nftables 或 eBPF 都可能实现 Service 数据面,实际规则与排查入口会不同。

节点本机访问 ClusterIP 也应该只看 PREROUTING#

不一定。本机进程发起的流量通常会走 OUTPUT;排查节点本机访问 Service 时,要检查 nat/OUTPUT,而不是只看 nat/PREROUTING。

小结#

三条链可以这样收束:

PREROUTING:进来先看,常做 DNAT;
FORWARD:路由后发现不是给本机,检查是否允许转发;
POSTROUTING:出去前看,常做 SNAT/MASQUERADE。

排查网络时,先判断数据包属于哪类路径:

访问本机:PREROUTING -> INPUT
本机发出:OUTPUT -> POSTROUTING
经过本机转发:PREROUTING -> FORWARD -> POSTROUTING

路径判断对了,再看具体 table 和规则,问题会清楚很多。

参考资料#

本文共 3924 字,创建于 Jun 28, 2026

相关标签: Linux, Kubernetes, DevOps, ByAI