使用 Pcap.Net 对 Ipv6 数据包进行分段

Posted

技术标签:

【中文标题】使用 Pcap.Net 对 Ipv6 数据包进行分段【英文标题】:Fragment Ipv6 packet using Pcap.Net 【发布时间】:2017-11-25 18:22:23 【问题描述】:

所以我为IpV4找到了这个解决方案:

private IEnumerable<Packet> SplitPacket(Packet packet, int numberOfFragments)

    IpV4Datagram ipV4Datagram = packet.Ethernet.IpV4;

    if (ipV4Datagram.Protocol == IpV4Protocol.Tcp || ipV4Datagram.Protocol == IpV4Protocol.Udp)
    
        EthernetLayer ethernet = (EthernetLayer)packet.Ethernet.ExtractLayer();
        ILayer layer = packet.Ethernet.IpV4.ExtractLayer();
        IpV4Layer ipV4Layer = (IpV4Layer)packet.Ethernet.IpV4.ExtractLayer();
        ipV4Layer.HeaderChecksum = null;
        DateTime packetTimestamp = packet.Timestamp;
        PayloadLayer payload = (PayloadLayer)packet.Ethernet.IpV4.Payload.ExtractLayer(); //extract the data
        int totalLength = payload.Length;
        int partialLength = totalLength / numberOfFragments; //split data into smaller segments
        partialLength = (partialLength / 8) * 8; //make sure it's divisible with 8
        if (partialLength == 0)
            partialLength = 8;
        //(http://en.wikipedia.org/wiki/IPv4#Fragmentation_and_reassembly)
        ushort offset = 0; //send one by one

        while (offset < totalLength)
        
            int fragmentLength = partialLength; //get length for this fragment
            IpV4FragmentationOptions options = IpV4FragmentationOptions.MoreFragments;

            if (offset + fragmentLength >= totalLength) //is this the last fragment ? trim length if needed
            
                options = IpV4FragmentationOptions.None;
                fragmentLength = totalLength - offset;
            

            byte[] newBuffer = ipV4Datagram.Payload.ToArray(); //copy the actual data into a new buffer
            PayloadLayer newPayload = new PayloadLayer  Data = new Datagram(newBuffer, offset, fragmentLength) ;
            ipV4Layer.Fragmentation = new IpV4Fragmentation(options, offset); //change IP layer fragmentation options
            Packet newPacket = null;

            if (packet.Ethernet.IpV4.Protocol == IpV4Protocol.Tcp)
            
                TcpLayer tcpLayer = (TcpLayer)packet.Ethernet.IpV4.Tcp.ExtractLayer();
                tcpLayer.Checksum = null;
                newPacket = PacketBuilder.Build(packetTimestamp, ethernet, ipV4Layer, tcpLayer, newPayload);
            
            else if (packet.Ethernet.IpV4.Protocol == IpV4Protocol.Udp)
            
                UdpLayer udpLayer = (UdpLayer)packet.Ethernet.IpV4.Udp.ExtractLayer();
                udpLayer.Checksum = null;
                newPacket = PacketBuilder.Build(packetTimestamp, ethernet, ipV4Layer, udpLayer, newPayload);
            

            yield return newPacket;
            //yield return PacketBuilder.Build(packetTimestamp, ethernet, ipV4Layer, tcpLayer, newPayload); //return
            offset += (ushort)fragmentLength; //next offset
        
    

由于Ipv6Layer 不包含IpV4layer 中的多个字段,例如IpV4FragmentationOptions,我想知道Fragmentation 是如何在IpV6 上实现的

【问题讨论】:

【参考方案1】:

来自Wikipedia:

碎片化

与 IPv4 不同,IPv6 路由器从不分段 IPv6 数据包。数据包 超过目的地的最大传输单元的大小 链接被丢弃,这种情况由数据包太大发出信号 ICMPv6 类型 2 消息到始发节点,类似于 IPv4 设置了 Don't Fragment 位时的方法。

IPv6 中的端节点应执行路径 MTU 发现以 确定要发送的数据包的最大大小,以及上层 协议预计会限制有效载荷大小。但是,如果 上层协议不能这样做,发送主机可以使用 片段扩展标头以执行端到端分片 IPv6 数据包。任何传输 IPv6 数据的数据链路层都必须是 能够传送包含 1280 字节的 IP 数据包,而无需 需要在 IP 层调用端到端的分片。

碎片化

包含原始(较大)数据包片段的数据包由 两部分:原始数据包的不可分段部分(即 所有片段都相同),以及 原始数据包,由片段偏移量标识。片段 第一个(“最左边”)片段的偏移量为 0。

数据包的不可分片部分由固定的标头和 原始数据包的一些扩展头(如果存在):全部 扩展标头,包括路由扩展标头,或 否则为逐跳扩展标头。如果扩展头都不是 目前,不可分割的部分只是固定的标题。

最后一个(扩展)标题的下一个标题值 unfragmentable 部分设置为 44 表示一个 Fragment 扩展 标题如下。在 Fragment 扩展头之后的一个片段 原始数据包的其余部分如下。

第一个片段包含其余的扩展标头(如果 展示)。之后,其余的有效载荷随之而来。每个片段都是 长度为 8 个八位字节的倍数,最后一个片段除外。

每个 Fragment 扩展标头都将其 M 标志设置为 1(表示 后面还有更多片段),除了最后一个,其标志设置为 0。

重新组装

原始数据包由接收节点通过收集重组 所有片段并将每个片段放置在正确的偏移量和 丢弃携带的数据包的分片扩展头 他们。包含分片的数据包不需要按顺序到达;他们 将由接收节点重新排列。

如果没有在收到后 60 秒内收到所有片段 第一个带有分片的数据包,原始数据包的重组是 丢弃,所有碎片都被丢弃。如果第一个片段是 收到(包含固定标头),超时消息 (ICMPv6 类型 3,代码 1)返回到发起 分片的数据包,如果数据包因此而被丢弃。

接收主机必须尽最大努力重新组装 重组后的分段 IP 数据报最多包含 1500 个 字节。允许主机尝试重新组装碎片 大于 1500 字节的数据报,但也允许 在它变得明显之后默默地丢弃任何数据报 重新组装的数据包将大于 1500 字节。因此,发件人 应避免发送完全重组的分段 IP 数据报 大小大于 1500 字节,除非他们事先保证 接收器能够重组如此大的数据报。

安全

研究表明,可以利用碎片化 逃避网络安全控制。因此,RFC 7112 要求 IPv6 数据包的第一个片段包含整个 IPv6 标头 链,使得一些非常病态的碎片化案例是 禁止。此外,作为对逃避的研究的结果 RFC 7113、RFC 6980 中的 RA-Guard 已弃用分片 使用 Neighbor Discovery,不鼓励使用碎片 安全邻居发现 (SEND)。​​

【讨论】:

以上是关于使用 Pcap.Net 对 Ipv6 数据包进行分段的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 PCap.NET 发送的数据包没有填写 TCP 选项?

如何将 Pcap.Net 数据包类对象导出到 .pcap 文件

我需要能够使用 Pcap.Net 填充 tcp 数据包的以太网层

使用 pcap.net 在同一网络中捕获不同 PC 的网络数据包

pcap.net ReceivePacket 无法正常工作

Pcap.net vs Sharppcap