操作系统内功 · 第 28 篇|netfilter 五条链:iptables 与 nftables 的内核真相

netfilter:协议栈上的五个关卡

第 27 篇的 skb 在协议栈里旅行时,会路过几个固定的检查点——netfilter 在这些点提供钩子,让内核模块(iptables/nftables/conntrack/NAT)注册回调,对包进行检查、修改、过滤。五个钩子点构成包路径上的五条「链」(chain):

flowchart TB
    IN[网卡收包] --> PREROUTING[PREROUTING 链]
    PREROUTING -->|"目标是本机"| INPUT[INPUT 链]
    PREROUTING -->|"目标是转发"| FORWARD[FORWARD 链]
    INPUT --> LOCAL[本机进程 / socket]
    LOCAL --> OUTPUT[OUTPUT 链]
    FORWARD --> POSTROUTING[POSTROUTING 链]
    OUTPUT --> POSTROUTING
    POSTROUTING --> OUT[网卡发包]
  • PREROUTING:路由判定之前——DNAT(改目的地址)必须在这里做,因为改的是路由的依据。
  • INPUT:包 destined 本机,进入本机进程之前——主机防火墙的主战场。
  • FORWARD:包途经本机转发——路由器/容器节点转发路径的过滤器。
  • OUTPUT:本机发出的包,路由判定后——本机出口过滤与 SNAT 前的检查。
  • POSTROUTING:发包的最后关卡——SNAT(改源地址)在这里做,包即将离手。

「链」这个名字容易误导:链不是独立存在的工作队列,而是协议栈路径上的固定挂点;链里的规则串行匹配。真正 organize 规则的是「表」(table)维度。

表 × 链:规则的二维矩阵

iptables 的规则按功能分成四张表,每张表只挂在部分链上,形成正交矩阵:

表 功能 典型用途 挂载的链
raw 绕过连接跟踪 高性能场景免 conntrack PREROUTING/OUTPUT
mangle 改包头(TTL、TOS、标记) 策略路由打标 全部五链
nat 地址转换 SNAT/DNAT/伪装 PREROUTING/OUTPUT/POSTROUTING
filter 过滤 防火墙规则 INPUT/FORWARD/OUTPUT

同一链上多张表的规则按优先级顺序执行:raw → mangle → nat → filter。理解这张矩阵,iptables 的命令就不再是咒语:iptables -t nat -A PREROUTING ... 的含义变成「在 nat 表的 PREROUTING 链(即路由判定前的 DNAT 时机)追加一条规则」。

一个高频混淆在此澄清:「本机 80 端口的包被 INPUT 链拦截」与「容器的 80 端口被 DNAT」走的是不同路径。容器端口映射(docker 的 -p 8080:80)实际是宿主机上的 DNAT 规则——外部包在 PREROUTING 被改写目的地址为容器 IP,然后走 FORWARD 链(对宿主机而言这是转发不是本机交付)。这就是为什么容器网络故障排查要看 nat 表的 PREROUTING 与 filter 表的 FORWARD,而 INPUT 链「什么都没配却依然不通」——流量根本没走 INPUT。

conntrack:连接跟踪与 NAT 的地基

netfilter 最有工程价值的模块是 conntrack(连接跟踪):为每条流(TCP/UDP/ICMP 各有等价语义)维护一条状态记录(五元组 → 状态、超时、NAT 映射),挂在 PREROUTING/OUTPUT 入口创建、POSTROUTING/INPUT 出口确认。

TCP 的状态机有固定的迁移图:NEW(首个 SYN)→ ESTABLISHED(握手完成)→ TIME_WAIT 等关闭态;UDP 用「双向超时」模拟流。这条状态机让防火墙规则可以用状态说话——-m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT 一条规则放行所有已建流的回包,只需对新建连接做精细控制。这是有状态防火墙与无状态 ACL 的本质区别。

NAT 完全建立在 conntrack 之上:只有流的第一条包真正走 NAT 规则,转换映射记入 conntrack;后续包查映射直接转换。这就是「NAT 网关为什么能承载海量并发」的机制答案——规则匹配只发生一次,热路径是 conntrack 表查找(哈希表,/proc/sys/net/netfilter/nf_conntrack_max 控制容量)。反向的坑也在同一处:conntrack 表满(table full, dropping packet 的 dmesg 告警)会导致新连接被丢弃而已建流不受影响——高并发 NAT 网关与 Kubernetes 节点(每个 Pod 连接都占表项)的著名故障,nf_conntrack_max 与超时参数(nf_conntrack_tcp_timeout_established)是容量规划的一部分。

规则匹配的性能模型:线性链与集合优化

iptables 单链内的规则是线性匹配:第 N 条规则的成本乘在每条包路径上。规则数一多(几百上千条,黑名单场景常见),每包成本线性膨胀。工程对策按层次:

  • ipset:把海量 IP/端口装进集合数据结构(哈希表),规则只写一条「匹配集合」——千条规则变一条,这是 iptables 时代黑名单的标准解。
  • 规则排序:高频命中的规则放链首(线性链的局部性优化)。
  • raw 表免跟踪:对确信无需状态的高频流量(如某些健康检查),raw 表 NOTRACK 省掉 conntrack 开销。

nftables(iptables 的官方继任者,内核 3.13+,完全替代于近年)从架构上解决了线性链问题:规则编译为虚拟机字节码在内核执行,集合与映射是一等公民(匿名集合内联在规则里),一条规则可同时匹配多协议(不再分 iptables/ip6tables/arptables/ebtables 四套工具)。语法层面 nft add rule inet filter input tcp dport 80 accept 与 iptables 同构,迁移成本低。新项目直接用 nftables;维护存量 iptables 时理解底层机制不变——五链四表的矩阵模型是两者共同的底层语义。

工程排查清单:防火墙问题的标准动线

# 看包到底被哪条规则处理(计数器是关键证据)
iptables -L -n -v          # 或 nft list ruleset
# 逐链追踪:给规则加日志
iptables -I INPUT 1 -p tcp --dport 8080 -j LOG --log-prefix "IN8080 "
dmesg | tail               # 看包有没有到这一条
# conntrack 状态与表压力
cat /proc/sys/net/netfilter/nf_conntrack_count
conntrack -L | grep <ip>   # 单条流的状态与 NAT 映射
# 容器网络专用:先看 DNAT 是否命中
iptables -t nat -L PREROUTING -n -v --line-numbers

排查心法三条:先确认包走了哪条路径(本机交付走 INPUT、转发走 FORWARD、被 DNAT 过的包看 nat 表)——一半的「防火墙不通」是路径判断错了;计数器优先于规则语义(规则「应该」命中不算数,pkts 计数为零才是事实);conntrack 状态先于规则检查(INVALID 状态被丢的包,规则写得再对也白搭)。

与本系列其他章节的勾连

conntrack 表与第 25 篇的 accept 队列、第 20 篇的 OOM 评分共享同一设计模式:内核用有界资源承载无界外部状态,容量规划因此成为运维职责。Kubernetes 的 kube-proxy iptables 模式(Service 的 ClusterIP 靠 nat 表规则实现)是本章矩阵模型的最大规模工业应用——数万条 Service 规则的线性匹配也是它被 IPVS/eBPF 模式取代的动因。容器网络的 DNAT 全景在下一篇展开:veth、bridge 与跨主机的完整拓扑。

NetworkPolicy 的内核路径:策略在容器网络上的实现

Kubernetes 的 NetworkPolicy(命名空间级的 Pod 间访问控制)是 netfilter 矩阵在编排层的又一次落地。iptables 实现(Calico 的 default 路径、kube-router):每个 Policy 编译成 ipset 集合加 iptables 规则,挂在 FORWARD 链——Pod 流量走第 29 篇画过的 veth 到 bridge 到 FORWARD 路径,逐条匹配源 Pod 集合与目标端口。规则数与 Policy 数线性相关,千级 Policy 的节点上 FORWARD 链退化成第 28 篇警告过的线性长链——Calico 的 Typha 与「策略聚合」优化都是在给这条链瘦身。eBPF 实现(Cilium):Policy 判决做成 BPF 程序挂在 veth 的 TC 层,规则是 BPF map 的查找(O(1)),且判决发生在「流量进入协议栈之前」——被拒绝的包不消耗 conntrack 与栈资源;附加收益是 L7 感知(HTTP 路径级别的策略)与 Hubble 的可视化观测。排障口径因此分两套:iptables 系看 FORWARD 链的命中计数与 ipset 集合成员,eBPF 系用 cilium policy trace 做判决回放(输入五元组,输出 ALLOW/DENY 与命中的规则)。一个高频事故模板值得记住:「Service 通了但 NetworkPolicy 不生效」——多数是 CNI 插件没装 Policy 支持组件(默认 Docker 网络根本不认 NetworkPolicy,装了 CNI 才有实现),先确认实现层存在再查规则,方向不要反。

规则之外:nftables 的 flowtable 与硬件卸载

netfilter 体系还有一条少人知道但量级惊人的加速路径:flowtable(流表卸载)。思路与 conntrack 的「首包走规则、后续查表」一脉相承但更彻底:流的首个包走完整协议栈(含 NAT 与过滤),flowtable 把这条流的转发信息(五元组、出口、改写规则)记入一张硬件友好的表;后续包在 PREROUTING 之后直接查 flowtable 转发,跳过 FORWARD 链、跳过大部分协议栈——路由器场景(软路由、K8s 节点转发、NFV 网关)的每包成本降到原路径的十分之一量级。nftables 原生支持(flowtable f { hook ingress priority 0; devices = { eth0, eth1; } } 一段配置),内核 4.16+ 可用,5.x 加入了硬件卸载接口(把 flowtable 条目下发到支持 flow steering 的网卡,进一步省掉内核的包搬运)。适用边界:flowtable 只加速转发流量(路由器形态),本机交付的流量(INPUT 路径)不走它;NAT 与过滤语义在首包固化,流中改规则不生效(长连接场景要配合 conntrack 的刷新机制)。对 K8s 工程师的实际意义:Cilium 的快速路径、kube-proxy 的部分优化、云厂商的节点转发加速,底层都是 flowtable 或它的变体——当节点转发吞吐上不去且 CPU 消耗在内核网络栈时,先确认 flowtable 是否可用(nft list flowtable),再考虑 XDP 重写,顺序不要反。

iptables 与 conntrack 的排障案例集

三个高频案例把本章机制钉进肌肉记忆。案例一「本机端口不通但规则全放行」:外部访问某端口超时,filter INPUT 全是 ACCEPT——tcpdump 抓包发现包到达后没有回包,iptables -L 看不出问题,最后在 nat 表 PREROUTING 找到一条旧的 DNAT 规则把包转发去了已下线的后端 IP。教训:端口类故障先画包路径(进本机还是被 DNAT 走了),nat 表与 filter 表都要看。案例二「高并发下间歇丢新连接」:业务高峰新连接成功率掉到 95%,连接数远没到上限——dmesg 里 nf_conntrack: table full, dropping packet 实锤;节点跑着大量 Pod 加出网代理,conntrack 默认 65536 不够用。修复:nf_conntrack_max 提到 262144、超时参数(tcp_timeout_established 从 5 天压到 2 小时)、监控加 conntrack_count/max 水位。案例三「规则改完立刻断连」:运维用逐条 iptables -D 删旧规则再 -A 新规则,中间几秒的规则空窗把长连接的回包放成了 INVALID 丢弃——连接全断。修复:改用 iptables-restore 原子替换(第 28 篇工程化),长连接场景再加 conntrack 的白名单保活。三个案例的共同复盘句式:「规则是对的、路径是错的」或「容量是对的、默认值是错的」——netfilter 的故障几乎不发生在规则语法层,发生在对包路径与容量默认值的误判上,这也是本章把机制讲这么细的原因。

小结

netfilter 在协议栈的五个固定挂点(PREROUTING/INPUT/FORWARD/OUTPUT/POSTROUTING)上承接四张表(raw/mangle/nat/filter)的规则,「链是路径上的挂点、表是规则的分类」这一句拆解了 iptables 的全部语法恐惧。conntrack 是有状态防火墙与 NAT 的地基:首包走规则建表、后续包查表直通,nf_conntrack_max 因此成为高并发节点的容量红线。nftables 用字节码虚拟机与一等公民的集合解决了线性链问题,是 iptables 的正牌继任者。工程化的三件事——原子生效(restore 加自动回滚)、规则版本化(git 加 CI)、计数器可观测——把防火墙从手艺活变成可靠的代码资产。

← 返回资讯列表

读者留言

COMMENTS 暂无
仅本站原创文章开放留言 · 请勿留下手机号、邮箱等个人信息

还没有留言,来说第一句?