如何使用 BPF 定位 TCP 数据包中的 MSS 值

How do I target the MSS value in a TCP packet using BPF

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

我想丢弃设置了 缺少 MSS 值的 syn 标志的数据包。在 iptables 中,MSS 的目标是 --tcp-option 2。我知道 MSS 在 TCP 选项中,从 TCP 数据包的字节 22 开始,MSS 是 'kind' 2。我可以通过在 BPF 语法中使用 tcp[22:2]==$NUMBER 来过滤 MSS。但是,我想要做的是将 MSS 完全丢失的 SYN 数据包作为目标。

我已经尝试了我能想到的 "null" 的每个变体,但我没有运气。

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

我尝试过的例子:

$ ./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

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从TCPheader中提取数据偏移字段,即TCPheader.
  • 中32bit字的个数
  • (tcp[12] & 0xf0) >> 2 将其乘以 4 得到字节数。
  • 如果您的 TCP header 中少于 21 个字节,那么您就知道没有 TCP 选项。
  • tcp[20] != 2 检查第一个 TCP 选项(从偏移量 20 开始)的 Option-Kind 字段是否不是 2,MSS 的 Option-Kind。

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

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