Linux Kernel/Netfilter xt_string / textsearch

跨 skb 数据块匹配过滤规则中的字符串

Netfilter 的 xt_string 在选择 kmp 后,以前缀表避免重复回溯,并保留匹配进度跨越同一 skb 的多个数据块。

v6.12通信与流量核验 2026-10-12
相关概念

工程问题#

字符串过滤规则需要在指定偏移范围内寻找字节模式,而 skb 的数据可能分散在多个内存块中。既要避免重复比较已经匹配的前缀,也不能因为模式跨过块边界就漏掉匹配。

实际实现#

规则安装时,string_mt_check 根据 conf->algo 调用 textsearch_prepare,并缓存模式的预处理结果。配置 kmp 时使用 kmp_ops 注册的实现;数据包匹配由 string_mt 调用 skb_find_text。kmp_find 逐块取得数据,以 q 记录已匹配的模式前缀;失配时依据 prefix_tbl 回退 q,q 在获取下一块时保持不变。

处理流程#

  1. 安装规则时选择 kmp,并按模式构建可复用的前缀表
  2. 对当前 skb 的指定偏移范围逐块取得待匹配字节
  3. 失配时回退到已有前缀的最长可用后缀,继续读取当前字节
  4. 保留 q 跨越数据块边界,找到完整模式后将位置交还过滤规则

源码片段#

固定版本 · 原文摘录
net/netfilter/xt_string.cv6.12 · L54–L62
查看原文件
54	if (conf->u.v1.flags & XT_STRING_FLAG_IGNORECASE)55		flags |= TS_IGNORECASE;56	ts_conf = textsearch_prepare(conf->algo, conf->pattern, conf->patlen,57				     GFP_KERNEL, flags);58	if (IS_ERR(ts_conf))59		return PTR_ERR(ts_conf);6061	conf->config = ts_conf;62	return 0;
string_mt_check · 预处理规则

规则检查时把算法名、模式和 flags 交给 textsearch_prepare,并将返回配置保留给后续数据包使用。

net/netfilter/xt_string.cv6.12 · L23–L34
查看原文件
23static bool24string_mt(const struct sk_buff *skb, struct xt_action_param *par)25{26	const struct xt_string_info *conf = par->matchinfo;27	bool invert;2829	invert = conf->u.v1.flags & XT_STRING_FLAG_INVERT;3031	return (skb_find_text((struct sk_buff *)skb, conf->from_offset,32			     conf->to_offset, conf->config)33			     != UINT_MAX) ^ invert;34}
string_mt · 数据包匹配入口

实际过滤路径对当前 skb 的配置范围调用 skb_find_text,并按规则处理反向匹配。

lib/ts_kmp.cv6.12 · L49–L69
查看原文件
49	for (;;) {50		text_len = conf->get_next_block(consumed, &text, conf, state);5152		if (unlikely(text_len == 0))53			break;5455		for (i = 0; i < text_len; i++) {56			while (q > 0 && kmp->pattern[q]57			    != (icase ? toupper(text[i]) : text[i]))58				q = kmp->prefix_tbl[q - 1];59			if (kmp->pattern[q]60			    == (icase ? toupper(text[i]) : text[i]))61				q++;62			if (unlikely(q == kmp->pattern_len)) {63				state->offset = consumed + i + 1;64				return state->offset - kmp->pattern_len;65			}66		}6768		consumed += text_len;69	}
kmp_find · 分块读取与前缀回退

q 在块循环外初始化,在不同 get_next_block 返回的数据块之间保持。失配时按前缀表回退,找到完整模式就返回其起始位置。

lib/ts_kmp.cv6.12 · L74–L89
查看原文件
74static inline void compute_prefix_tbl(const u8 *pattern, unsigned int len,75				      unsigned int *prefix_tbl, int flags)76{77	unsigned int k, q;78	const u8 icase = flags & TS_IGNORECASE;7980	for (k = 0, q = 1; q < len; q++) {81		while (k > 0 && (icase ? toupper(pattern[k]) : pattern[k])82		    != (icase ? toupper(pattern[q]) : pattern[q]))83			k = prefix_tbl[k-1];84		if ((icase ? toupper(pattern[k]) : pattern[k])85		    == (icase ? toupper(pattern[q]) : pattern[q]))86			k++;87		prefix_tbl[q] = k;88	}89}
compute_prefix_tbl

按模式本身构建前缀表;失配时复用已有前缀信息,与搜索阶段的回退规则对应。

lib/ts_kmp.cv6.12 · L130–L143
查看原文件
130static struct ts_ops kmp_ops = {131	.name		  = "kmp",132	.find		  = kmp_find,133	.init		  = kmp_init,134	.get_pattern	  = kmp_get_pattern,135	.get_pattern_len  = kmp_get_pattern_len,136	.owner		  = THIS_MODULE,137	.list		  = LIST_HEAD_INIT(kmp_ops.list)138};139140static int __init init_kmp(void)141{142	return textsearch_register(&kmp_ops);143}
kmp_ops / init_kmp

将名字 kmp、初始化函数和查找函数注册到 textsearch,连接配置选择和具体实现。

五段原文展示规则安装、包匹配、块间状态、前缀表和注册机制;也保留同版 ts_bm.c 的上下文,支持对分块行为的比较。

收益与取舍#

工程分析

带来的收益

  • 长度 m 的模式预处理为 O(m),单次搜索长度 n 的输入为 O(n),每条规则保留 O(m) 的模式和前缀信息
  • 在同一 skb 的非连续数据块之间保持匹配进度,无须为 KMP 先拼出一个连续大缓冲区

付出的代价

  • 每条规则都要保存模式与前缀表;匹配多条规则时并不是一次共享的多模式扫描
  • 逐字节扫描不保证在所有流量与模式分布上快于跳跃式匹配算法
  • 字节级大小写处理不等同 Unicode 文本匹配,范围外数据也不会参与本次搜索

可比较的选择

Linux textsearch 的 Boyer–Moore 实现可以利用跳跃减少比较,但该版本文件明确提醒:跨多个输入块的模式可能匹配不到;不能只比较算法名字而忽略分块行为。

先合并缓冲区再搜索便于使用要求连续内存的算法,但可能增加复制、分配和缓冲区生命周期成本。

版本与适用范围#

对应 Linux v6.12 的 xt_string,明确限定规则算法为 kmp。这里的“跨块”是同一次 skb 文本搜索中的内存数据块,不能解释为重组任意多个 TCP 包、解密 TLS 或按应用协议解析数据;这些不由本例 KMP 完成。规则支持偏移范围、忽略大小写和反向匹配,完整检查逻辑在 xt_string.c。

参考来源#

源码、官方文档与原始论文
01
linux · string_mt_check / string_mt

net/netfilter/xt_string.c · string_mt_check / string_mt

源码v6.12
02
linux · kmp_find / compute_prefix_tbl / kmp_ops

lib/ts_kmp.c · kmp_find / compute_prefix_tbl / kmp_ops

源码v6.12
03
linux · Boyer–Moore 分块匹配边界说明

lib/ts_bm.c · Boyer–Moore 分块匹配边界说明

源码v6.12
12 个匹配案例