2

我正在尝试解决 ESP 数据包碎片化的问题,因为在添加 ESP 标头后超出了 MTU 大小。解决方案(每个人都这样做)是在进行 ESP 加密之前进行分段。

我的问题是,如果这很有用,为什么 Linux IPSec 实现本身不支持它。我了解 L4 流量选择器无法工作的某些限制。但并不是每个人都使用它。

此外,如果您可以分享有关添加此支持的最佳方式的任何指示,那将真的很有帮助。

谢谢。

4

1 回答 1

1

为了完成这个循环(并希望帮助可能正在寻找类似解决方案的人),我们通过使用libnetfilter_queue解决了我们的问题。我们面临的挑战是,我们无法访问应用程序的源代码,否则我们可以在应用程序级别本身完成碎片。

这是我们内部文件的相关摘录,由Sriram Dharwadkar编写,他也进行了实施。其中一些引用是我们内部应用程序的名称,但不要认为您在理解上有任何问题。

最终解决方案

NetFilter Queues是用户空间库,它提供 API 来处理内核数据包过滤器排队的数据包。愿意使用此功能的应用程序应动态链接到netfilter_queuenfnetlink,并包括来自 sysroot-target/usr/include/libnetfilter_queue/ 和 sysroot-target/usr/include/libnfnetlink/ 的必要标头。需要添加以NFQUEUE为目标的iptables。NFQUEUE 是一个 iptables 和 ip6tables 目标,它将对数据包的决定委托给用户空间软件。例如,下面的规则将要求一个监听用户空间程序对所有排队的数据包做出决定。

iptables -A INPUT -j NFQUEUE --queue-num 0

在用户空间中,软件必须使用 libnetfilter_queue api 连接到队列 0(默认队列)并从内核获取消息。然后它必须对数据包作出裁决。
当一个数据包到达一个 NFQUEUE 目标时,它被排入与 --queue-num 选项给出的数字相对应的队列中。数据包队列被实现为链表,其中元素是数据包和元数据(Linux 内核 skb):

  • 它是一个固定长度的队列,实现为数据包的链表
  • 存储由整数索引的数据包
  • 当用户空间向相应的索引整数发出判决时,数据包被释放
  • 当队列已满时,没有数据包可以入队
  • 用户空间可以读取多个数据包并等待给出判决。如果队列未满,则此行为没有影响
  • 数据包可以无序判断。用户空间可以读取数据包 1,2,3,4 并按顺序在 4,2,3,1 处判断
  • 太慢的判决将导致一个完整的队列。然后内核将丢弃传入的数据包而不是将它们排队。
  • 内核和用户空间之间使用的协议是 nfnetlink。这是一个基于消息的协议,不涉及任何共享内存。当数据包入队时,内核将包含数据包数据和相关信息的 nfnetlink 格式化消息发送到套接字。用户空间阅读此消息并发出判决

Prefragmentation 逻辑在 AvPreFragApp(新应用程序)和 Security Broker(现有控制器应用程序)中实现。
在安全代理中,一旦建立隧道。将以下两条规则添加到 RAW 表中。

对于 TCP 预分片:

/usr/sbin/iptables -t raw -I OUTPUT 1 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1360

以上规则在三向握手期间协商适当的 MSS 大小。可以安全地假设,1360+TCPH+IPH+ESP+IPH <= 1500,因此加密后不会发生碎片。

对于 UDP 预分片

/usr/sbin/iptables -t raw -I OUTPUT 2 -s <tia> -p udp -m mark !--mark 0xbeef0000/0xffff0000 -j NFQUEUE

上述规则将所有 src ip 为 TIA(隧道地址)的 udp 数据包排队,并将不等于 0xbeef0000 标记到 netfilter 队列以供应用程序处理。AvPreFragApp 将在所有排队的 udp 数据包上标记 0xbeef0000。这样做是为了避免数据包的重复排队。

AvPreFragApp

AvPreFragApp 应用程序使用 netfilter 队列来处理由 NFQUEUE 目标排队的数据包。如上所述,将具有 TIA 作为 src ip 的 udp 数据包排队的 iptables 规则已添加到安全代理中。此规则在隧道建立时添加,并在使用新 TIA 的隧道反弹时更新。因此,所有以 TIA 为源 ip 的数据包都排队等待 AvPreFragApp 处理。

  • AvPreFragApp 从 libnetfilter_queue 调用一组 api 来设置队列并将数据包从内核复制到应用程序
  • 在创建队列时,传递回调函数地址,一旦数据包进入队列等待处理,该地址就会被调用
  • 需要设置 NFQNL_COPY_PACKET 模式,它将整个数据包从内核复制到应用程序
  • 可以使用 netfilter 队列处理程序获取文件描述符。使用recv函数可以得到包缓冲区
  • 在处理数据包时,AvPreFragApp 检查数据包的大小。如果数据包大小 <= 1376。给出接受判决。此外,如果设置了 DF 位,则会给出 ACCEPT 判决
  • 如果数据包大小 > 1376 并且未设置 DF 位,则给出 DROP 判决。这意味着原始数据包被丢弃。但在此之前,数据包将被复制到应用程序缓冲区。现在 AvPreFragApp 在应用程序中进行分片。所有这些片段都被写入带有标记 0xbeef0000 的原始套接字。sendmsg 用于将数据包写入原始套接字
  • 这些预先分段的数据包被加密并 ESP 封装在内核中。

注意:TIA:隧道内部地址,逻辑 IPSec 接口。

于 2016-01-11T05:10:57.320 回答