首页 > 解决方案 > 如何使用 BPF 定位 TCP 数据包中的 MSS 值

问题描述

我正在学习 BPF 并将一些 iptables 规则转换为 BPF 字节码。我主要使用 nfbpf_compile 应用程序来执行此操作,而不是尝试编写 C 或汇编程序。我很幸运,但一条规则的语法让我无法理解。

我想丢弃设置了 syn 标志但缺少 MSS 值的数据包。在 iptables 中,MSS 以--tcp-option 2. 我知道 MSS 在从 TCP 数据包的第 22 个字节开始的 TCP 选项中,并且 MSS 是“种类”2。我可以使用tcp[22:2]==$NUMBERBPF 语法过滤 MSS。但是,我想做的是针对完全丢失 MSS 的 SYN 数据包。

我已经尝试了所有我能想到的“null”变体,但没有运气。

有谁知道! --tcp-option 2BPF 语法中 iptables 的等价物吗?

我尝试过的一个例子:

$ ./nfbpf_compile RAW 'tcp[22:2]==0x0'  (I know this won't work..it's an example)
12,48 0 0 0,84 0 0 240,21 0 8 64,48 0 0 9,21 0 6 6,40 0 0 6,69 4 0 8191,177 0 0 0,72 0 0 22,21 0 1 0,6 0 0 65535,6 0 0 0

# iptables -I INPUT -m bpf --bytecode '12,48 0 0 0,84 0 0 240,21 0 8 64,48 0 0 9,21 0 6 6,40 0 0 6,69 4 0 8191,177 0 0 0,72 0 0 22,21 0 1 0,6 0 0 65535,6 0 0 0
' -j DROP

标签: iptablesbpf

解决方案


TL;DR如果您知道只有 0 或 1 个 TCP 选项,或者如果您知道 MSS 选项始终是第一个选项,那么您可以使用以下过滤器:

tcp && (tcp[tcpflags] == tcp-syn) && ((((tcp[12] & 0xf0) >> 2) < 21) || tcp[20] != 2)

如果您不知道这一点(有几个 TCP 选项并且 MSS 选项可能是其中任何一个),通常情况下,我认为不可能用 nfbpf_compile 的语法表达匹配过滤器。在这种情况下,我建议编写一个 C 程序并使用-m bpf --object-pinned /path/to/pinned/bpf.


让我先解释一下上面的过滤器。您有两种情况要匹配:1) 没有 TCP 选项或 2) 第一个 TCP 选项不是 MSS:

  • tcp[12] & 0xf0从 TCP 头中提取数据偏移字段,即 TCP 头中 32 位字的数量。
  • (tcp[12] & 0xf0) >> 2将此乘以 4 以获得字节数。
  • 如果您的 TCP 标头中少于 21 个字节,那么您知道没有 TCP 选项。
  • tcp[20] != 2检查第一个 TCP 选项的 Option-Kind 字段(从偏移量 20 开始)不是 2,即 MSS 的 Option-Kind。

为什么一般情况更难匹配?TCP 选项的长度是可变的(取决于它们的 Option-Kind),并且 TCP 选项的数量是可变的。假设您想扩展上述过滤器以匹配第二个 TCP 选项。您首先需要知道该选项从哪里开始;第一个选项具有可变长度,因此这不是固定偏移量。

使用 cBPF(由 nfbpf_compile 发出的 BPF 字节码),您可以通过将当前选项偏移量存储在 X 寄存器中,然后使用第二种寻址模式将一个字节加载到寄存器 A 中来表达这一点(参见Linux 文档,BPF engine and instruction set)。但是,我认为您不能使用有限的 nfbpf_compile 语法来做到这一点(假设它与 tcpdump 的语法相同)。


推荐阅读