为什么Linux IPSec实现在加密之前不支持碎片?

时间:2015-02-05 07:27:07

标签: linux linux-kernel ipsec ip-fragmentation

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

我的问题是,如果它非常有用,为什么Linux IPSec实现本身不支持它。我知道L4流量选择器不会起作用的某些限制。但并非每个人都能利用它。

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

感谢。

1 个答案:

答案 0 :(得分:1)

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

这里是 Sriram Dharwadkar 编写的内部文件的相关摘录,他们也做了实施。一些参考文献是我们的内部应用程序名称,但不要认为您在理解方面应该有任何问题。

最终解决方案

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

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

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

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

预碎片化逻辑在AvPreFragApp(新应用程序)和安全代理(现有控制器应用程序)中实现。
在安全代理中,一旦隧道建立。以下两条规则被添加到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&lt; tia&gt; -p udp -m mark! --mark 0xbeef0000 / 0xffff0000 -j NFQUEUE

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

AvPreFragApp

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

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

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