[协议分析] IP分片(碎片)重组简单概念

    链路层具有最大传输单元MTU这个特性,它限制了数据帧的最大长度,不同的网络类型都有一个上限值。以太网的MTU是1500,可以用 netstat -i 命令查看这个值。如果IP层有数据包要传,而且数据包的长度超过了MTU,那么IP层就要对数据包进行分片(fragmentation)操作,使每一片的长度都小于或等于MTU。我们假设要传输一个UDP数据包,以太网的MTU为1500字节,一般IP首部为20字节,UDP首部为8字节,数据的净荷(payload)部分预留是1500-20-8=1472字节。如果数据部分大于1472字节,就会出现分片现象。

      当提交给数据链路层进行传送时,一个IP分片或一个很小的无需分片的IP数据报称为分组。数据链路层在分组前面加上它自己的首部,并发送得到的帧。

IP首部(5-8字节)包含了分片和重组所需的信息:
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |         Identification            |R|DF|MF|    Fragment Offset    |
  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  |<-------------16-------------->|<--3-->|<---------13---------->|

Identification:发送端发送的IP数据包标识字段都是一个唯一值,该值在分片时被复制到每个片中。
R:保留未用。
DF:Don't Fragment,“不分片”位,如果将这一比特置1 ,IP层将不对数据报进行分片。
MF:More Fragment,“更多的片”,除了最后一片外,其他每个组成数据报的片都要把该比特置1。
Fragment Offset:该片偏移原始数据包开始处的位置。偏移的字节数是该值乘以8。

两个Flags和Fragment Offset结合使用,进行分片时,DF比特设置为0,表示可以进行分片,这时如果 MF的值为1,则表示当前IP报文是一个IP包的其中一段分片,并且不是最后一个分片,这时结合Fragment Offset域继续判断;如果MF为1而 Fragment Offset = 0,表示该IP报文为第一个分片,而且后续有分片;如果MF为1而Fragment Offset不是0,表示该IP报文为中间的一个分片;如果MF为0而Fragment Offset不是0,表示该报文是最后一个分片。

另外,当数据报被分片后,每个片的总长度值要改为该片的长度值。

可举例说明IP分片重组的过程。
假设分片前报文IHL=5, Total Length = 800, MF = 0, Fragment Offset = 0, MTU为512;
则分片报文1的IHL1 = 5, Total Length1 = 508, MF = 1, Fragment Offset1 = 0;
分片报文2的IHL2 = 5, Total Length2 = 312, MF = 0, Fragment Offset2 = 61。
    其中Total Length1 + Total Length2 = 508+312 = 820,比 Total Length多出的20字节为新增的IP头,并且由于偏移量的单位为8Byte,所以非尾片的净荷长度都是8Byte的整数倍,MTU为512Byte,去除IP头IHL*4 = 5*4 = 20Byte后得到512-20 = 492Byte, 492Byte不是8Byte的整数倍,就取488Byte,加上IP头得到488+20 = 508Byte。由于报文1的净荷为488Byte,所以报文2的Fragment Offset就是 488/8 = 61, Total Length2 为总净荷长度(Total Length -IHL*4 = 800-20 = 780Byte)减去报文1的净荷长度488Byte加上报文2的IP头20Byte得到780-488+20 = 312Byte。

同样可假设重组前报文1的IHL = 5, Total Length1 = 1012 , MF = 1, Fragment Offset1 = 0;
报文2的IHL = 5, Total Length2 = 312, MF = 0, Fragment Offset2 = 124。
则重组后的报文IHL = 5, Total Length = 1304, MF = 0, Fragment Offset = 0。
    其中报文1的净荷长度为Total Length1 – IHL1*4 = 1012-20 = 992Byte, Fragment Offset1 = O, MF = 1,表示报文1有后续报文并且报文1的后续报文偏移量应该是0*8 + 992 = 992Byte,而报文2的 Fragment Offset2 = 124,则偏移量为124 * 8 = 992Byte,所以报文1和报文2是相连的,并且MF = 0 表示报文2为最后一个分片,此时就得到了原来的报文重组完成,重组后的报文 MF = 0, Fragment Offset = 0,Total Length 为报文1的净荷长度(992Byte)加上报文2的净荷长度(Total Length2 –IHL*4 = 312 - 20 = 292Byte)加上IP报文头20Byte为992 + 292 + 20 = 1304Byte。

你可能感兴趣的:(c/c++编程日记)