所以我找到了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
答案 0 :(得分:0)
来自Wikipedia:
<强>碎片强>
与IPv4不同,IPv6路由器永远不会分裂IPv6数据包。包 超过目的地最大传输单位的大小 链路被丢弃,这个条件由Packet太大发出信号 ICMPv6类型2消息到源节点,类似于IPv4 设置Do not Fragment位时的方法。
IPv6中的终端节点应该执行路径MTU发现 确定要发送的数据包的最大大小,以及上层 协议有望限制有效载荷大小。但是,如果 上层协议无法这样做,发送主机可能会使用 片段扩展标头,以执行端到端的碎片 的IPv6数据包。传输IPv6数据的任何数据链路层都必须是 能够提供包含1280字节的IP数据包而无需 需要在IP层调用端到端的碎片。
<强>粉碎强>
包含原始(较大)数据包片段的数据包 两部分:原始数据包的不可分段部分(即 对于所有片段都是一样的),以及片段的一部分 由片段偏移标识的原始数据包。碎片 第一个(“最左边”)片段的偏移量为0。
数据包的不可分段部分包括固定标头和 原始数据包的一些扩展头(如果存在):全部 扩展标头,包括路由扩展标头,或 否则是Hop-by-Hop扩展头。如果两个扩展标头都不是 目前,不可分割的部分只是固定的标题。
最后一个(扩展名)标题的Next Header值 不可分段的部分设置为44表示片段扩展 标题如下。 Fragment扩展头之后的一个片段 其余的原始数据包如下。
第一个片段包含其余的扩展标头(如果 当下)。之后,其余的有效载荷随之而来。每个片段都是 除最后一个片段外,长度为8个八位字节的倍数。
每个Fragment扩展标头的M标志设置为1(表示 更多片段跟随),除了最后一个,其标志设置为0。
<强>重组强>
接收节点通过收集重新组装原始数据包 所有碎片并将每个碎片放置在右侧偏移处 丢弃携带的数据包的Fragment扩展头 他们。包含片段的数据包不需要按顺序到达;他们 将由接收节点重新安排。
如果不是在收到后60秒内收到所有碎片 带有片段的第一个数据包,重新组装原始数据包 被遗弃,所有碎片都被丢弃了。如果第一个片段是 收到(包含固定标头),超时时间消息 (ICMPv6类型3,代码1)返回到发起的节点 碎片包,如果因为这个原因丢弃了包。
接收主机必须尽最大努力重新组装 碎片化的IP数据报,重组后最多包含1500个 字节。允许主机尝试重新组合碎片 数据报大于1500字节,但也允许它们 在它变得明显之后,默默地丢弃任何数据报 重组的数据包大于1500字节。因此,发件人 应该避免发送重新组合的碎片化IP数据报 大小超过1500字节,除非他们事先得到保证 接收器能够重新组装这样大的数据报。
安全强>
研究表明,可以利用碎片的使用 逃避网络安全控制。因此,RFC 7112要求 IPv6数据包的第一个片段包含整个IPv6标头 链,这是一些非常病态的碎片案例 禁止。此外,作为对逃避的研究的结果 RFC 7113中的RA-Guard,RFC 6980已经弃用了碎片 使用邻居发现,并且不鼓励使用碎片 安全邻居发现(SEND)。