04 netfilter 与包过滤机制与实现详解

04 netfilter 与包过滤机制与实现详解

1. 概述

net/netfilter/~253 文件)是 Linux 包过滤、连接跟踪、NAT、负载均衡 的核心实现。它在协议栈 固定 hook 点 介入 sk_buff 路径,不改变网卡驱动;与 NAPI/收包 正交,作用于 L3 已解析之后 的转发/本地交付决策。

项目 说明
源码路径 rk3588/kernel-6.1/net/netfilter/
配置 CONFIG_NETFILTER 及子项(见 Kconfig
用户态 nft(nftables)、iptables(legacy)、conntrack
控制通道 NETLINK_NETFILTERnfnetlink.c
RK3588 无 Rockchip 专属补丁;行为与上游 6.1 一致

1.1 目录结构(按功能)

1
2
3
4
5
6
7
8
9
10
11
net/netfilter/
├── core.c # Hook 框架(注册、nf_hook_slow)
├── nfnetlink.c # NETLINK_NETFILTER 总线
├── nf_conntrack_*.c # 连接跟踪
├── nf_nat_*.c # NAT / 伪装
├── nf_tables_*.c nft_*.c # nftables
├── x_tables.c xt_*.c # iptables 扩展
├── nf_queue.c nf_log.c # 队列到用户态 / 日志
├── nf_flow_table_*.c # 快速转发路径
├── ipset/ # 高效匹配集合
└── ipvs/ # LVS 负载均衡

注意:IPv4/IPv6 的 iptables 表驱动net/ipv4/netfilter/net/ipv6/netfilter/(如 ip_tables.cip6_tables.c),但 hook 框架与 nftables 主体在 net/netfilter/


2. Hook 框架(core.c

2.1 Hook 点(IPv4/IPv6 _inet)

定义于 include/uapi/linux/netfilter.h

Hook 典型位置
NF_INET_PRE_ROUTING 路由决策前(入站)
NF_INET_LOCAL_IN 本机接收
NF_INET_FORWARD 转发
NF_INET_LOCAL_OUT 本机发出
NF_INET_POST_ROUTING 路由后、出接口前
NF_INET_INGRESS 入口(netdev 早期)
本机转发网卡收包L2 解封装NF_INET_PRE_ROUTING路由NF_INET_LOCAL_INNF_INET_FORWARD协议栈 / socketNF_INET_LOCAL_OUTNF_INET_POST_ROUTINGdev_queue_xmit

协议栈调用示例(net/ipv4/ip_forward.c):

1
2
return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, net, NULL, skb,
in, out, ip_forward_finish);

2.2 注册与存储

  • nf_register_net_hook() / nf_register_net_hooks():按 priority 插入 hook 数组
  • (netns, pf, hooknum) 维护 nf_hook_entries(RCU 只读遍历)
  • CONFIG_JUMP_LABELnf_hooks_needed[pf][hook] 无 hook 时跳过 nf_hook_slow 快速路径

nf_hook_ops 关键字段:

1
2
3
4
5
6
7
struct nf_hook_ops {
nf_hookfn *hook; /* 回调 */
u8 pf; /* NFPROTO_IPV4 / IPV6 / INET ... */
unsigned int hooknum;
int priority; /* 数值越小越先执行 */
void *priv;
};

2.3 nf_hook_slow() — 核心裁决

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state,
const struct nf_hook_entries *e, unsigned int s)
{
for (; s < e->num_hook_entries; s++) {
verdict = nf_hook_entry_hookfn(&e->hooks[s], skb, state);
switch (verdict & NF_VERDICT_MASK) {
case NF_ACCEPT:
break;
case NF_DROP:
kfree_skb_reason(skb, SKB_DROP_REASON_NETFILTER_DROP);
return ret;
case NF_QUEUE:
ret = nf_queue(skb, state, s, verdict);
// ...
default:
return 0; /* NF_STOLEN 等 */
}
}
return 1; /* 全部 ACCEPT → 调用 okfn */
}
Verdict 含义
NF_ACCEPT 继续下一个 hook 或 okfn
NF_DROP 丢弃 skb
NF_STOLEN hook 接管 skb,协议栈不再处理
NF_QUEUE 交用户态队列裁决(nf_queue.c
NF_REPEAT 重新从当前 hook 执行

内联入口 nf_hook()include/linux/netfilter.h)在 static_key 显示无 hook 时直接 okfn(skb)


3. 连接跟踪(nf_conntrack)

3.1 核心文件

文件 作用
nf_conntrack_core.c 表项创建/查找/GC、nf_conntrack_in
nf_conntrack_proto_*.c TCP/UDP/ICMP 等 L4 状态机
nf_conntrack_expect.c 期望连接(FTP/SIP 等多通道)
nf_conntrack_helper.c + nf_conntrack_ftp.c ALG 辅助
nf_conntrack_netlink.c 用户态查询/事件

3.2 nf_conntrack_in() 流程

挂于 PREROUTINGLOCAL_OUT 等(由 nf_conntrack_l3proto 注册):

1
2
3
4
5
nf_conntrack_in(skb)
→ get_l4proto() 定位 L4
→ resolve_normal_ct() 查表或新建 nf_conn
→ nf_conntrack_handle_packet() 更新 TCP 状态等
→ skb->_nfct 绑定连接

连接以 五元组 tuple(可加 zone)哈希入 nf_conntrack_hash;状态如 NEW / ESTABLISHED / RELATED

3.3 与 NAT 关系

  • conntrack 独立于 NAT,但 NAT 修改 tuple 必须同步 conntrack(nf_nat_core.c
  • nf_nat_hook 通过 RCU 指针在 core.c 中挂接,避免模块循环依赖

4. NAT(nf_nat)

文件 作用
nf_nat_core.c SNAT/DNAT 查找、tuple 改写
nf_nat_proto.c 协议相关校验和/端口映射
nf_nat_masquerade.c MASQUERADE(出接口地址)
nf_nat_redirect.c REDIRECT(本机端口)
nf_nat_ftp.c NAT helper

NAT 在 POSTROUTING(SNAT)/ PREROUTING(DNAT)hook 修改 skb 地址端口,并 nf_conntrack_alter_reply() 维护反向 tuple。


5. nftables(现代推荐)

5.1 组成

Makefilenf_tables-objs

  • nf_tables_core.c — 规则求值 nft_do_chain()
  • nf_tables_api.c — 表/链/规则/集合的 netlink 配置 API
  • nft_chain_filter.c / nft_chain_route.c / nft_chain_nat.c — 链类型与 hook 绑定
  • nft_*.c — 表达式:payload、cmp、lookup、ct、nat、limit、queue…
  • nft_set_*.c — 集合后端:hash、bitmap、rbtree、pipapo(x86 可有 AVX2)

5.2 规则求值:nft_do_chain()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv)
{
const struct nft_chain *chain = priv;
// 从 RCU blob 遍历规则
for (; rule < last_rule; rule = nft_rule_next(rule)) {
nft_rule_dp_for_each_expr(expr, last, rule) {
// fast path: nft_cmp_fast_eval, nft_payload_fast_eval ...
expr_call_ops_eval(expr, &regs, pkt);
if (regs.verdict.code != NFT_CONTINUE)
break;
}
// NFT_JUMP / NFT_GOTO / NF_ACCEPT / NF_DROP ...
}
}
  • 规则编译为 字节码 blob(表达式序列),求值用 nft_regs 寄存器
  • jump stack 支持 jump/goto 子链
  • gencursor 双缓冲:用户态更新规则时 RCU 切换,数据面无锁读

5.3 Hook 注册

nft_chain_filter.cnft_do_chain_ipv4 注册到各 NF_INET_* hook:

1
[NF_INET_FORWARD] = nft_do_chain_ipv4,

nf_tables_api.cnft_chain_hook 管理 base chain 与 nf_register_net_hook 的绑定。

5.4 用户态配置

1
2
3
nft add table ip filter
nft add chain ip filter forward { type filter hook forward priority 0 \; }
nft add rule ip filter forward tcp dport 22 accept

内核路径:nftNFNL_SUBSYS_NFTABLESnfnetlink)→ nf_tables_api.c


6. iptables / x_tables(legacy)

组件 路径 说明
x_tables x_tables.c match/target 注册框架
xt_*.c net/netfilter/xt_*.c 扩展:conntrack、mark、limit、LOG…
ip_tables net/ipv4/netfilter/ip_tables.c filter/nat/mangle 表
nft_compat nft_compat.c 可选:iptables 规则转 nft 后端

xt_conntrack.c 依赖 nf_conntrackxt_set.c 依赖 ipset


nfnetlink.c 实现 NETLINK_NETFILTER,子系统分发表 table[NFNL_SUBSYS_*]

子系统 用途
NFNL_SUBSYS_NFTABLES nft 表/链/规则
NFNL_SUBSYS_CTNETLINK conntrack 查询/事件
NFNL_SUBSYS_IPSET ipset 管理
NFNL_SUBSYS_QUEUE NFQUEUE
NFNL_SUBSYS_HOOK hook 查询(新)

每 netns:netlink_kernel_create(net, NETLINK_NETFILTER, &cfg)

详见 10-netlink内核用户通信机制与实现详解.md


8. 辅助子系统

8.1 ipset(ipset/

  • ip_set_core.c:集合类型注册、ip_set_test/add/del
  • 类型:hash:iphash:netbitmap:port 等(ip_set_hash_*.c
  • xt_set / nft_lookup 做大规模地址/端口匹配

8.2 nf_flow_table(快速转发)

nf_flow_table_core.c + nft_flow_offload.c

  • 对已 ESTABLISHED 连接缓存 flow_offload 条目
  • 后续包可 绕过部分协议栈 直接转发(可硬件 offload)
  • 依赖 conntrack tuple

8.3 ipvs(ipvs/

Linux Virtual Server:L4 负载均衡,独立 hook 与调度器(rr、wlc、mh 等),与 filter/NAT 可叠加。

8.4 nf_queue / nf_log

  • nf_queue.cNF_QUEUE verdict 将 skb 送用户态(如 iptables -j NFQUEUE
  • nf_log.c / nfnetlink_log.c:LOG/NFLOG 目标

9. 模块依赖关系(简化)

core.c Hook 框架nf_tables / nft_*nf_conntracknf_natx_tables / xt_*ipsetnfnetlink

10. 调试与 sysctl(常用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 规则
nft list ruleset
iptables -L -n -v

# 连接跟踪
cat /proc/net/nf_conntrack
sysctl net.netfilter.nf_conntrack_max

# 统计
cat /proc/net/stat/nf_conntrack
nft monitor trace # 需内核 trace 支持

# drop 原因(较新内核)
# SKB_DROP_REASON_NETFILTER_DROP

11. RK3588 场景

场景 关注点
网关/路由器 nf_conntrack_max、FORWARD 链默认 policy、MASQUERADE
Android/嵌入式 iptables-legacy 或 nft;热点 NAT
容器 netns 隔离;每 netns 独立 nft 表与 conntrack
性能 规则数量、nf_flow_table、避免过多 xt_recent/hashlimit
WiFi AP bridge + iptables FORWARD;或 nft forward chain

net/netfilter/ 内 RK 补丁;板级差异来自 defconfigCONFIG_NF_* 开关)与用户态规则。


12. 源码索引

主题 路径
Hook 注册/执行 net/netfilter/core.c
nf_hook 内联 include/linux/netfilter.h
conntrack 入口 net/netfilter/nf_conntrack_core.cnf_conntrack_in
NAT net/netfilter/nf_nat_core.c
nft 求值 net/netfilter/nf_tables_core.cnft_do_chain
nft 配置 API net/netfilter/nf_tables_api.c
nft hook 绑定 net/netfilter/nft_chain_filter.c
nfnetlink net/netfilter/nfnetlink.c
ipset net/netfilter/ipset/ip_set_core.c
flow offload net/netfilter/nf_flow_table_core.c
IPv4 iptables net/ipv4/netfilter/ip_tables.c

13. 相关文档


14. 小结

问题 答案
netfilter 在哪介入? 协议栈 NF_INET_* hook 点,对 sk_buff 裁决
框架核心文件? core.cnf_hook_slow
现代防火墙 API? nftablesnf_tables + nft_*
状态防火墙基础? nf_conntrack + 可选 nf_nat
如何配置? 用户态 nft/iptablesNETLINK_NETFILTER
与驱动关系? 无直接耦合;仅处理已进入网络栈的包

文章互动

阅读 --

留言

0 条留言

正在加载留言…