Netfilter 与 BPF/XDP

本页目录

端口转发已配置,却只放行 INPUT,连接仍不通。先确定报文怎样经过路由与 hook,再讨论规则、跟踪和 NAT;XDP/TC 又位于不同处理层次。

查阅目标阅读位置
报文路径与链控制流第 1~2 节
隔离规则实验与 conntrack第 3~4 节
NAT、BPF 与卸载观测第 5~7 节

1. 先判断包走哪条路径

本机接收、本机发送和转发经过不同 hook PREROUTING 外部报文入口 路由决定 本机 / 转发 INPUT 送往本机协议栈 FORWARD 转发报文 POSTROUTING 出口处理 OUTPUT 本机产生的报文 OUTPUT 前通常已有初始路由;规则修改地址或 mark 可能要求重新路由。

发往本机服务的外部报文常经 PREROUTING、INPUT;本机进程发出的报文经 OUTPUT、POSTROUTING;路由转发的报文经 PREROUTING、FORWARD、POSTROUTING。桥接、netdev ingress、隧道和卸载存在其他路径,不能说所有报文一定遍历全部五个 hook。

DNAT 在路由之前改变目标地址,可以使原本发给网关地址的流量变成向内网服务器转发。因此端口转发后的报文通常需要 FORWARD 规则,而不是只添加 INPUT 放行。

同一 hook 中按数值从小到大的 priority 执行;不同 base chain 可共享 hook,但相同 priority 的相对顺序不应成为策略依赖。参见 Netfilter hooks。

2. nftables 的 table、chain、rule 与 set

对象职责
family指定协议/处理域,例如 ip、ip6、inet、bridge、netdev
table组织 chain、set、map 等对象,本身不是固定执行阶段
base chain绑定 hook、priority 和 policy,成为执行入口
regular chain通过 jump/goto 等规则进入,不自行绑定 hook
rule顺序求值的匹配表达式与动作
set / map表达集合查询或键到值的映射,减少重复规则

nftables 仍会按链中的规则顺序求值,并非完全摆脱线性规则检查。集合可以改善表达和特定查询效率,但不能无条件声称“任意 nft 规则集都只遍历一次且比 iptables 快”。

iptables 命令还可能使用 nft backend,不能仅凭命令名字判断底层是 legacy xtables;多套工具共同管理时应确认实际 backend 和当前 ruleset。

accept 为什么不总是最终通行证

在某条 base chain 中 accept 结束该链相应处理,但后续同 hook 的其他 base chain 或更后面的 hook 仍可拒绝。drop 通常立即终止该报文继续处理。regular chain 的 return/jump 与 base chain policy 又是不同控制流。

执行位置对该来源的动作是否已经最终放行
input base chain,priority 0accept SSH尚未,后续链仍会处理
input base chain,priority 10drop 该来源报文被拒绝

两条链共同决定结果。在前一条链末尾重复加 accept,不能覆盖后一条的 drop。见 nftables chain 配置。

下面固定两个不同优先级的 base chain,分别改变目标端口与来源条件。一个 chain 的 accept 之后,后续 chain 仍可拒绝;drop 则使后面的规则失去执行机会。

正在呈现知识画面
前一条链 accept,为何后一条仍能 drop?

accept 结束当前 base chain 的处理,后续链仍可拒绝;drop 终止这条路径。多个同 hook 的 base chain 按 priority 由小到大执行。

3. 一个仅计数的学习规则集

保存为 observe.nft。它不改变默认接受策略,分别统计从三个主要路径经过该链的包;不是完整安全策略。

 table inet kb_observe {
     chain input {
         type filter hook input priority 0; policy accept;
         counter
     }
     chain forward {
         type filter hook forward priority 0; policy accept;
         counter
     }
     chain output {
         type filter hook output priority 0; policy accept;
         counter
     }
 }

可以在支持非特权 user/network namespace 的机器上,用全新网络 namespace 检查并加载:

unshare --user --map-root-user --net sh -eu -c '
    nft -c -f observe.nft
    nft -f observe.nft
    nft list table inet kb_observe
'

-c 检查而不应用事务,但仍需要内核相关支持和权限。这里没有连接任何外部接口,namespace 随进程结束回收;如果系统禁用非特权 namespace,该例会失败,不应直接改成在宿主防火墙加载。实际抓流量还需在同一 namespace 中建立测试接口和负载。

nft 的批量事务可避免用户态逐条命令造成部分更新窗口,但不意味着已有 conntrack/NAT 状态也随规则变化一起重建。

4. Conntrack 状态不是 TCP socket 状态

conntrack 记录协议、双向 tuple、zone、状态及计时等,既能处理 TCP,也可给 UDP 等无连接协议建立流跟踪。ct state established 与 ss 显示的 TCP ESTAB 不是同一个状态机。

NEW、ESTABLISHED、RELATED、INVALID、UNTRACKED 描述跟踪视角。RELATED 可包括关联 ICMP 错误或受控 helper 建立的关系;notrack 需要在足够早的位置执行,且会改变依赖跟踪的 NAT/规则行为。

表项的创建、确认、超时和销毁不同于应用 socket 的打开关闭。观察表满时,应检查新流速率、超时、zone、内存和异常流量,不能默认只提高 nf_conntrack_max 就解决问题。count/max 是容量观测,不是端到端健康指标。

5. NAT 建立映射,后续包复用状态

典型有状态 NAT 用流的首包建立 binding,后续包根据 conntrack 中保存的映射转换,不是每个包都重新遍历 NAT 链选择一条新映射。修改 NAT 规则后,已有流因此可能继续使用旧映射。

方向地址变化
客户端发起10.0.0.8:40000 访问 198.51.100.20:443
网关源转换源地址变为 203.0.113.5:51000
返回流量发往网关 51000,按反向状态还原到客户端 40000

这些地址只用于推演。回包的还原依赖已有映射,不能只把 NAT 理解成单方向字符串替换。

SNAT 通常在出口选择源映射;MASQUERADE 根据出口接口地址工作,并有接口状态变化相关处理。DNAT 常在 PREROUTING/OUTPUT 改目标。不要把 nat INPUT 链写成“给本机的 DNAT”通用位置;它支持的源转换用途应单独理解。

映射之外:转发许可与回程路由仍需成立

NAT 不自动启用 IP forwarding、修复回程路由或允许 FORWARD。hairpin 访问还可能需要相应源转换,以使返回流量经过同一状态设备。见 NAT 文档。

6. XDP 与 TC:处理位置决定可用信息

native XDP 位于驱动早期接收路径,可以在较少协议栈开销下丢弃、发回或重定向报文;generic XDP 已处于 skb 路径,硬件 offload 又依网卡支持。三者不能混成固定的“skb 前 hook”。

XDP_PASS 表示继续后续栈处理;XDP_TX 表示从接收设备发回;XDP_REDIRECT 依赖正确的重定向目标和相关准备。返回动作不是创建路由、修改 MAC、更新校验和、维护连接跟踪的完整替代品。

TC 处理 skb,适合结合队列、分类、地址修改和重定向等功能。direct-action 使用 TC_ACT_*,不能复制 XDP 常数当返回值。socket filter 控制交给 socket 的接收数据,不是“socket 创建 hook”。

BPF helper 对 conntrack、路由等有受限接口,但可用性和责任依类型/版本而异,不能认为程序默认继承整套 Netfilter 状态和规则。程序类型参阅 eBPF 程序类型。

7. 流量卸载会改变可观测路径

Netfilter flowtable 和硬件 offload 可让已建立流走更短路径。首包的策略建立、后续流量的实际经过位置和计数因此需要一起分析;某条 FORWARD 计数器没有逐包增加,不一定代表所有流量停止。

抓包为空:先定位观察点,再判断报文是否到达

同理,XDP 提前丢包可能发生在常规 packet socket 抓包点之前。本机 tcpdump 看不到,既可能是报文没来,也可能是更早就被处理。排查时结合物理端口计数、XDP/TC 状态、Netfilter trace/counter 和 socket 状态,按层缩小范围。见flowtable 文档。